Escolar Documentos
Profissional Documentos
Cultura Documentos
DESENVOLVENDO
INTELIGENTEMENTE COM
JAVASERVER® FACES
JavaServer Faces (JSF) é um framework de componentes de interface de usuário (UI) para aplicações
web Java 2 Enterprise Edition que, uma vez adotado, permite às empresas migrar de tecnologias
ultrapassadas, como: terminais virtuais (VTs) baseados em caracteres, para tecnologias e plataformas
atualizadas e baseadas em padrões, como JSF e Java. Durante os últimos 15 anos, a indústria de software
viu muitas tecnologias e plataformas aparecerem e sumirem. Normalmente, a utilização de determinada
tecnologia diminui por várias razões, incluindo moda e competição. Outra razão comum para a queda de
certas tecnologias é o fato de serem projetadas e mantidas por uma única empresa, então os consumidores
destas tecnologias são forçados a confiar no suporte provido apenas pelos criadores. Sempre que um criador
decide tornar obsoleta uma tecnologia em favor de outra solução mais avançada, o consumidor é deixado
com uma plataforma desatualizada e sem suporte. O JSF permite às empresas e consumidores aproveitarem
as últimas tecnologias assim que surgem, com o mínimo impacto nas aplicações JSF existentes. JSF
também adiciona extremo reuso de funcionalidade e aparência visual à indústria de software. A parte 1
deste livro vai ensiná-lo o que é JSF, além de descrever como aprimorar o JSF através do desenvolvimento
de seus próprios componentes e abrir seus olhos para um novo horizonte.
CAPÍTULO 1
A FUNDAÇÃO DO JSF:
COMPONENTES
JavaServer Faces (JSF) é um framework de interface de usuário (UI) para aplicações web em Java.
Foi criado para facilitar, de maneira significativa, a escrita e manutenção de aplicações que rodam
em um Java application Server e apresentam suas UIs de volta para um cliente específico.
– Especificação do JavaServer Faces
Para aqueles, dentre vocês, que não tiveram chance de conhecer JSF antes de ler este livro, este capítulo
lhes dará uma introdução rápida à sua funcionalidade fundamental. Se já for familiarizado com JSF, ainda
sim poderá encontrar discussões sobre componentes e arquitetura de ciclo de vida interessante, pois estes
tópicos são fundamentais para sua compreensão do resto do livro. Este capítulo cobrirá o desenvolvimento
de aplicativos, mostrará um resumo de JSF e como se relaciona com outros frameworks similares, além
de examinar profundamente a arquitetura JSF e seu modelo de componentes. Ao final deste capítulo você
deverá entender a arquitetura JSF, seus blocos fundamentais e seu ciclo de vida de request.
Antes de pular dentro da arquitetura do JSF, vamos definir a audiência para JSF (e, em última forma,
para este livro). A especificação JSF define os tipos de desenvolvedores que compõem a audiência
primordial: criadores de páginas, desenvolvedores de aplicações, criadores de componentes, fornecedores
de ferramentas e implementadores de JSF, como mostrado na tabela 1-1.
Tipo Descrição
Page author (autor de páginas) Um page author é responsável pela criação da UI e tem conhecimento
de linguagens de markup e script, assim como a tecnologia de apre-
sentação, como JavaServer Pages (JSP). De acordo com a especificação
JSF, este tipo de desenvolvedor geralmente não está familiarizado
com linguagens de programação como: Java ou Visual Basic.
Application Developer Um application developer, de acordo com a especificação JSF, está
(desenvolvedor de aplicações) a cargo da funcionalidade Server-side de uma aplicação que pode
ou não estar relacionada com a UI. Os skills técnicos de um applica-
tion developer geralmente incluem Java, Enterprise JavaBeans (EJBs)
ou outras tecnologias de servidores.
Continuação
4 PRO JSF E AJAX
Tipo Descrição
Component writer Um component writer é o fornecedor principal de componentes
(criador de componentes) reutilizáveis. Este desenvolvedor é responsável pela criação de bi-
bliotecas de componentes que possam ser utilizadas por outros, como
o page author.
Tools provider Um fornecedor de ferramentas, como diz o nome, fornece ferramen-
(fornecedor de ferramentas) tas que auxiliem o desenvolvedor que cria aplicações com JSF
JSF implementers Um JSF implementer é um desenvolvedor que fornece o executável
(implementadores de JSF) (ou a implementação de uma especificação JSF) para todos os desen-
volvedores definidos anteriormente. Exemplo de implementações
disponíveis são: Sun Reference Implementation (RI) (http://
java.sun.com/j2ee/javaserverfaces/) e Apache MyFaces (http://
myfaces.apache.org).
Em nossa experiência, os page authors e application developers são, normalmente, a mesma pessoa,
logo, eles conhecem desenho de UI e linguagens de programação, como Java ou Visual Basic. Neste livro,
focalizaremos a maior parte da nossa atenção nos component writers.
Durante estes anos de evolução o perfil de distribuição de uma aplicação, assim como a tecnologia de
computadores e software utilizada para desenvolvê-la, mudaram.
projetada e desenvolvida para tarefas de um único usuário (single user) e carecia de colaboração nos dados
comuns; neste ponto não existiam bancos de dados centrais ou emails. Aplicações distribuídas ou instaladas
desta forma são referidas como aplicações one tier (Nota de tradução: também conhecidas como monolíticas).
Sob o ponto de vista de manutenção, esta solução one-tier é uma aplicação que reside na máquina de
um indivíduo que controla a interação com a lógica de negócios. Estas aplicações one-tier integram todas
as três camadas de aplicação conhecidas (apresentação, lógica de negócios e dados), tornando sua
manutenção difícil e o compartilhamento e escalabilidade da informação quase impossíveis.
Two-Tier: Cliente-Servidor
As soluções two-tier (ou cliente-servidor) se apresentaram no centro do palco nos anos 80 e
empurraram as soluções one-tier para os arquivos da história. A arquitetura two-tier, que permite
compartilhar dados, mudou a forma como as aplicações eram desenvolvidas e distribuídas. As aplicações
two-tier interagem diretamente com o usuário final; as lógicas de apresentação e negócios são armazenadas
no cliente e os dados em um servidor remoto. Esta arquitetura permite a múltiplos usuários acessarem os
dados centrais, com aplicações como: clientes de email (como Microsoft Outlook ou Mozilla Thunderbird).
Embora a solução two-tier resolva o problema de múltiplos usuários acessarem a mesma fonte de dados
(data source), também tem as suas limitações, como a falta de flexibilidade do projeto com relação a
modificações ou porte (Nota de tradução: portar, neste contexto, significa mudar de plataforma), a qual,
por sua vez, aumenta os custos de manutenção.
Neste cenário, o desenvolvedor de aplicativos é obrigado a fornecer não apenas uma aplicação, mas
três. Esta arquitetura contém uma aplicação para a interface Web, outra para o dispositivo móvel e,
finalmente, uma para o dispositivo Telnet (um terminal VT). Todas as três aplicações usam sua própria
pilha de tecnologias, o que será um pesadelo de manutenção para o desenvolvedor e o administrador, e
poderão causar problemas de segurança e escalabilidade. Para o desenvolvedor de aplicações surge uma
questão: “Quantas tecnologias terei que aprender para criar uma solução completa para o meu projeto?”
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 7
Frameworks
Comparados a dez anos atrás, os clientes de hoje possuem demandas muito maiores e requerimentos
mais específicos para novos projetos de aplicações Web. Eles requerem aplicações Web ricas e mais
amigáveis, com segurança intrínseca, acessibilidade, internacionalização, portabilidade etc. As aplicações
multitier devem disponibilizar, de maneira bem sucedida, todas essas características, não importando a
complexidade crescente dos cenários de falhas adicionais e, também, crescentes requisitos de escalabilidade
e segurança.
A crescente complexidade da criação de aplicações implica necessidade de simplicidade. Até agora,
no reino J2EE, não há uma escolha clara de tecnologia para aplicações Web. As interfaces de programação
de aplicações (APIs), como JSP e servlets, não fornecem abstração suficiente do trabalho bruto de se
implementar uma aplicação multitier. Para atender a estes requisitos e fornecer algum nível de simplicidade,
a indústria evoluiu em uma direção na qual as comunidades open source e as empresas de software estão
fornecendo aos desenvolvedores de frameworks para protegê-los da complexidade introduzida pelas
aplicações multitier.
Nota: IoC significa que você registrou alguma parte do seu código com o framework, e ele irá
invocar o seu código quando o cliente o requisitar (Nota de tradução: esta característica
é também conhecida como “CallBack”). Isto também é referido como O princípio de
Hollywood (“Não nos chame. Nós o chamaremos”).
No cenário de software para varejo (veja a figura 1-1), os frameworks podem ajudar a aumentar a
produtividade do desenvolvedor e facilitar a manutenção, mas os frameworks também são incompatíveis
uns com os outros, o que torna a integração difícil de se lidar. Em contraste, o JSF é um framework padrão
que objetiva resolver esta incompatibilidade.
8 PRO JSF E AJAX
INTRODUÇÃO AO JSF
Resumidamente, JSF é um framework de componentes UI para aplicações J2EE. Antes de iniciarmos
a falar sobre componentes UI (e por componentes UI queremos dizer blocos de construção para
desenvolvedores, e não os componentes do framework em si), vale a pena discutir o motivo pelo qual você
necessita de mais um framework. JSF tenta, entre outras coisas, resolver os mesmos problemas que os
anteriormente mencionados Apache Tapestry e Oracle ADF UIX, ambos frameworks que estão
disponíveis há algum tempo e se provaram bem sucedidos.
O diferencial que o JSF traz, o qual não existem em frameworks similares, é o suporte de uma
especificação padrão (JSR-127). O fato do JSF ser parte da especificação do padrão J2EE, torna prioritário
para os maiores fornecedores de ferramentas J2EE do mercado (incluindo Oracle, IBM, Borland e Sun)
suportá-lo, o que, por sua vez, garantirá a sua ampla adoção e suporte das ferramentas.
Muitas aplicações Web ainda estão presas nos anos 90, quando muito esforço era alocado às tarefas de
encanamento básico (nota de tradução: prover infra-estrutura, comunicação entre componentes etc) e não nos
componentes de alto nível (de abstração). Basicamente, quando há pouca ou nenhuma abstração sobre o código,
o desenvolvimento de aplicações Web torna-se complicado e difícil de manter. Você pode investir muito tempo
na aplicação para torná-la rica e interativa usando várias tecnologias, como: applets, plug-ins (Flex), HTML
dinâmico (DHTML) e JavaScript. Quando utilizadas juntas, estas tecnologias podem resultar em uma aplicação
Web poderosa e interativa; mas como você mantém tal aplicação? Como você reutiliza o que criou?
Modelo de Componentes
O JSF traz para a mesa o melhor framework J2EE. O JSF veio para simplificar a vida dos
desenvolvedores de aplicativos, tornando possível a eles focalizarem na apresentação, sem a necessidade
de conhecer o código e os scripts por baixo dela. Eles sentirão o aumento na produtividade com o JSF ao
utilizarem componentes UI que ocultam a maior parte do trabalho bruto de integração de funcionalidade
rica nas aplicações Web. O objetivo é fornecer um caminho fácil para criar UIs a partir de um conjunto
de componentes UI reutilizáveis.
Estes componentes reutilizáveis vêm em várias formas com diferentes funcionalidades, desde
componentes de layout (como o layout de uma página inteira) até botões simples. Os desenvolvedores de
aplicações podem utilizar estes componentes para criar uma página e aninhar componentes UI, uns dentro
dos outros, para obter o efeito desejado; por exemplo, aninhar campos de texto e botões em um componente
de layout de linha (row layout) renderizará os componentes aninhados em uma única linha no cliente. Esta
estrutura de componentes aninhados é freqüentemente conhecida como relacionamento parent-to-child
(pai para filho) e visualizada como uma hierarquia de componentes UI. Esta hierarquia de componentes
UI representa a descrição de uma página JSF em runtime.
Modelo de Navegação
O JSF fornece um modelo de navegação declarativo, o qual permite aos desenvolvedores de aplicações
o ajuste das regras de navegação de modo a definir a navegação de uma view para outra em uma aplicação
Web. As regras de navegação no JSF são definidas dentro do arquivo de configuração do JSF, faces-
config.xml, e são direcionadas a cada página. O exemplo de código 1-1 mostra uma regra de navegação
configurada no faces-config.xml.
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 9
<navigation-rule>
<from-view-id>/login.jspx</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/result.jspx</to-view-id>
</navigation-case>
</navigation-rule>
No exemplo de código 1-1, uma regra é criada de modo que a partir de uma view, login.jspx, no caso
de um resultado success (sucesso), o usuário será direcionado a uma página chamada result.jspx. O
resultado é o valor de retorno de uma ação realizada na aplicação, como um botão sendo pressionado. No
JSF, uma ação é anexada ao UIComponent, o que permite um controle fino sobre a página. Estas ações
podem ter sua própria regra de navegação ou compartilhar a mesma regra.
Nesta arquitetura, apenas uma aplicação está servindo três diferentes agenes usando três diferentes
RenderKits - Hypertext Markup Language (HTML), Wireless Markup Language (WML) e Telnet. Na
prática, a aplicação provavelmente seria composta de três páginas diferentes mas com uma diferença
principal; todas seriam construídas com a mesma tecnologia - JSF e Java. Isto poupará tempo de
desenvolvimento e reduzirá a manutenção. Além disto, e talvez mais importante, o JSF estabelece padrões,
os quais são criados para serem utilizados pelas ferramentas (como JDeveloper da Oracle, Studio Creator
da Sun e plug-ins para Eclipse, como Exadel Studio) para fornecerem aos desenvolvedores a facilidade
de uso há muito tempo sonhada pela comunidade de desenvolvedores J2EE.
Arquitetura do JSF
Visto de um satélite, o JSF implementa o que é conhecido como padrão Model 2, o qual é baseado
na arquitetura MVC. Se observar como o padrão Model 2 é aplicado em uma aplicação JSF, verá que ele
consta de três elementos - a view, o modelo de navegação e a lógica da aplicação, como na figura 1-3.
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 11
Model (Modelo)
Com o JSF o conceito de managed bean (bean gerenciado) foi criado. O managed bean é a cola da lógica
da aplicação – código de apoio (backing code) ou bean de apoio (backing bean. Os managed beans são
definidos no aquivo faces-config.xml e dão ao desenvolvedor de aplicação acesso total a todos os métodos
mapeados do backing bean. Este conceito de IoC é bem sucedido em frameworks, como Spring, HiveMind
e o Oracle ADF model binding (JSR-227). A característica de managed bean é responsável pela criação
dos backing beans ou outros beans, como Data Access Objects (DAO). No JSF, um backing bean é um
objeto Java simples (POJO) com nenhuma dependência de interfaces ou classes específicas de implementações.
O previamente mencionado JSF controller – o FacesServlet – não está ciente de qual ação foi tomada; ele
está ciente apenas do resultado de uma ação em particular e irá utilizá-lo para decidir para onde navegar.
No JSF é o componente que fica ciente de qual ação ou método devem ser invocados no caso de um evento
de usuário. O Exemplo de Código 1-2 mostra um managed bean definido no arquivo faces-config.xml.
<managed-bean>
<managed-bean-name>sample</managed-bean-name>
<managed-bean-class>
com.apress.projsf.ch1.application.SampleBean
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
12 PRO JSF E AJAX
O Exemplo de Código 1-2 define um backing bean, sample, que aponta para uma classe chamada
com.apress.projsf.ch1.application.SampleBean. O <managed-bean-scope> indica onde a instância deste
bean será armazenada depois de criada – request, session ou application. O exemplo de código também
tem uma opção none para bean que não deve ser armazenado em escopo algum, mas, ao invés disto, ser
instanciado novamente em cada acesso. A tabela 1-2 lista todos os escopos disponíveis.
View (Visão)
A camada view do JSF descreve o layout pretendido, o comportamento e a renderização da aplicação.
Uma das peças-chave de uma aplicação JSF é o UIComponent. UIComponents são a base da camada view
do JSF e representam comportamento e estrutura de uma aplicação. Um desenvolvedor deverá utilizar estes
UIComponents para criar uma aplicação através do aninhamento de componentes uns dentro dos outros.
Esta estrutura aninhada será representada, em tempo de execução (runtime), por uma hierarquia de
componentes, como mostrado na figura 1-4, a qual, por sua vez, representa a view ou UI, de maneira
semelhante ao desenvolvimento de uma aplicação baseada em Swing.
A descrição de página default da especificação JSF é JSP, mas nada existe na especificação JSF que
impeça um implementador de fornecer descrições de páginas alternativas, como Extensible Markup
Language (XML), WML ou HTML. Utilizar JSP como descrição de página tem seus lados bom e mau.
No lado bom, é uma solução popular e conhecida; como tal, aprender como criar aplicações JSF e JSP
representa uma pequena curva de aprendizado para a maioria dos desenvolvedores J2EE. Adicionalmente,
como um bônus, a adoção de JSF como a tecnologia de view para novas aplicações web é boa. A
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 13
conseqüência é que o JSF tem dependência de JSP, de tal forma que é necessário trabalhar com ciclos de
vida diferentes de uma aplicação que é parcialmente JSP e parcialmente JSF. Mais adiante neste capítulo
(veja a seção “JSF e JSP”) falaremos sobre estas diferenças e sobre o impacto que têm nas aplicações
construídas com a sintaxe JSP e componentes JSF.
Controller (Controlador)
O JSF vem com um controller simples – FacesServlet. O FacesServlet age como um despachante,
controlando o fluxo de navegação e despachando requests para as páginas JSF apropriadas.
Nota: O JSF é todo componentes – e componentes reutilizáveis! O JSF foi divulgado primeira-
mente em Março de 2004 e teve um release subseqüente 1.1, em agosto de 2004. A JSR
inicial (JSR-127) foi substituída pela JSR-252, a qual trouxe o release do JSF 1.2.
Para ilustrar o benefício de separar a UI e os modelos de dados, vamos ver um exemplo do elemento
comum de formulário HTML <select> . Este elemento de lista possui um atributo multiple que altera o
comportamento de seleção simples para múltipla seleção de opções. Este modelo não tem separação de
renderização e comportamento. Para que um desenvolvedor de aplicação possa alterar o comportamento
do elemento de simples seleção para múltipla seleção, ele deve fazer um ajuste – simplesmente alterar o
atributo multiple. Entretanto, isto terá um impacto enorme na lógica de aplicação, já que os valores passados
pelo cliente agora serão representados por uma lista de chave-valor, ao invés de apenas um único par chave-
valor.
Os componentes UI UISelectOne e UISelectMany são bons exemplos de separação clara entre
comportamento e aparência. Por exemplo, o UISelectOne tem um comportamento distinto para selecionar
um valor único a partir de várias opções, e o UISelectMany tem um comportamento para selecionar muitos
valores de uma lista de opções. O componente UISelectOne tem três tipos de renderers – Listbox, Radio
e Menu. Alterar a aparência de Radio para Menu não afetará o comportamento da aplicação.
Entretando, se os desenvolvedores de aplicação desejarem alterar o comportamento de um componente
de seleção múltipla, podem substituir o componente JSF UISelectOne pelo componente JSF UISelectMany
ao invés de simplesmente alterar um atributo no código da página, como fariam com o elemento <select>
diretamente. Esta separação clara entre alterar o comportamento de um componente JSF e alterar sua
aparência dá aos desenvolvedores de aplicação melhor entendimento do impacto de suas alterações quando
modificarem a definição da página. A figura 1-6 ilustra o UIComponent e três RenderKits com aparências
diferentes.
Uma boa regra para seguir é, antes de iniciar um projeto de componentes, pesquisar na Web componentes
prontos. Na maioria dos casos você, provavelmente, vai resolver escrevendo um novo Renderer para um
componente já existente, e já existe um bom número de componentes. Se não conseguir encontrar o componente
que está procurando, então deverá criar o seu próprio. Para criar um novo componente você deve estar certo
de que ele introduz um novo comportamento, funcionalidade ou definição, e que o componente tem um
comportamento diferenciado do lado do servidor. Se o componente existe e você apenas necessita de uma nova
aparência, então crie um novo Renderer (por exemplo para usar Ajax com um componente de entrada de dados).
Vamos ver as diferentes partes que formam um componente JSF.
UIComponent
A base de todos os componentes JSF são as classes abstratas UIComponent e UIComponentBase. A classe
UIComponent (javax.faces.component.UIComponent) define o contrato comportamental e informação de
estado para todos os componentes, e a classe UIComponentBase (javax.faces.component.UIComponentBase)
é uma classe de conveniência que implementa quase todos os métodos da classe UIComponent. Uma descrição
simples de um UIComponent é um JavaBean normal com properties, events e listeners.
A especificação JSF define um conjunto de subclasses padrões de UIComponent,ou superclasses
comportamentais (UISelectOne e UISelectMany, por exemplo), que estendem a classe UIComponentBase.
Na maioria dos casos os criadores de componentes irão estender essas subclasses padrões de UIComponent.
Entretanto, eles podem derivar a classe UIComponentBase também. Um componente JSF consiste de um
UIComponent e um ou mais Renderers. É importante entender que as subclasses padrões de UIComponent
definem apenas comportamentos genéricos, independentes de renderer, como UISelectOne. A tabela 1-
3 resume os UIComponents comportamentais padrões e listas suas subclasses de conveniência associadas,
renderer types e tags JSP.
Para cada combinação de UICompontent e Renderer, existe uma subclasse específica para o renderer,
também chamada de classe de conveniência (convenience class). Uma implementação padrão de JSF, como
a Sun RI ou o runtime do MyFaces, vem com um conjunto de renderers para HTML (fornecidos pelo
RenderKit padrão de HTML) e um conjunto de subclasses específicas para o renderer HTML, como
HtmlSelectOneRadio.
Esta subclasse é opcional, mas é uma boa prática fornecê-la juntamente com o componente JSF, uma
vez que, às vezes, os desenvolvedores de aplicação possam desejar utilizá-la por conveniência, e para
escritores de componentes é difícil saber se os desenvolvedores de aplicação tentarão usá-la.
Uma vez que esta classe de conveniência estende o UIComponent e a superclasse comportamental
(UISelectOne, por exemplo) em runtime, a instância do componente não somente conterá informação
disponível nessa classe de conveniência como também informação estendida das classes UIComponent.
Se olhar para o modelo de herança utilizado pelo JSF para criar uma instância de um componente, parecerá
como a figura 1-7.
Este modelo permite acesso programático a todas as propriedades e atributos definidos pelas diferentes
classes que formam o componente. Como mencionado anteriormente, a classe UIComponentBase contém
acordos comportamentais para todos os componentes, a subclasse UISelectOne contém propriedades e
métodos específicos para o seu comportamento (selecionar apenas um, por exemplo), e a subclasse
específica para o renderer (HtmlSelectOneListbox, por exemplo) contém getters e setters para todos os
atributos específicos para o renderer, como também o rendererType de um componente em particular.
<h:form>
<h:selectOneRadio binding=”#{sample.selectOneRadio}” >
<f:selectItem itemLabel=”Jonas” itemValue=”jonas.jacobi” />
<f:selectItem itemLabel=”John” itemValue=”john.fallows” />
<f:selectItem itemLabel=”Duke” itemValue=”java.dude” />
</h:selectOneRadio>
<h:commandButton value=”Select Duke”
actionListener=”#{sample.onAction}” />
</h:form>
18 PRO JSF E AJAX
Na tag JSP selectOneRadio, ou custom action (ação customizada), o atributo binding recebe uma
expressão de ligação – #{sample.selectOneRadio}. Esta expressão indica uma propriedade de um backend
JavaBean – selectOneRadio – que, por sua vez, está ligada à instância do UIComponent criada por este
tag JSP. O Exemplo de Código 1-4 mostra o backend JavaBean, ou o managed bean, que contém a lógica
da página que, em runtime, selecionará a opção default no componente selectOneRadio para java.dude,
sempre que o usuário clicar o command button.
package com.apress.projsf.ch1.application;
import javax.faces.event.ActionEvent;
import javax.faces.component.html.HtmlSelectOneRadio;
No Exemplo de Código 1-4, o managed bean está utilizando a subclasse específica de renderer
HtmlSelectOneRadio. Se os desenvolvedores de aplicação quiserem alterar a UI e substituir o componente
selectOneRadio pelo selectOneMenu na página, uma exception do tipo class cast será levantada em runtime.
O desenvolvedor de aplicação pode evitar isto utilizando a classe ancestral do componente selectOneRadio
- UISelectOne. O Exemplo de Código 1-5 mostra como a página e o código-fonte do managed bean seriam
de acordo com a recomendação.
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 19
<body>
<h:form>
<h:selectOneRadio binding=”#{sample.selectOne}” >
<f:selectItem itemLabel=”Jonas” itemValue=”jonas.jacobi” />
<f:selectItem itemLabel=”John” itemValue=”john.fallows” />
<f:selectItem itemLabel=”Duke” itemValue=”java.dude” />
</h:selectOneRadio>
<h:commandButton value=”Select Duke”
actionListener=”#{sample.onAction}” />
</h:form>
</body>
O Exemplo de Código 1-5 contém a mesma descrição de página, exceto por um pequeno ajuste na
expressão de value-binding. Para ser mais genérico, o nome do método do managed bean foi alterado para
selecOne, ao invés de selectOneRadio, logo, a expressão na descrição de página foi alterada para referenciar
um nome de propriedade do backend bean mais genérico, como mostrado no Exemplo de Código 1-6.
package com.apress.projsf.ch1.application;
import javax.faces.event.ActionEvent;
import javax.faces.component.UISelectOne;
O novo managed bean está aproveitando a herança de componentes para tornar as alterações de UI
mais agnósticas. Ao invés da classe de conveniência HtmlSelectOneRadio, ele utiliza a superclasse
comportamental UISelectOne. Os desenvolvedores de aplicação podem agora mudar para outro compo-
nente na mesma família de componentes sem temer a quebra da lógica da aplicação.
Exemplo de Código 1-7. Utilizando o Mapa de Atributos de Componente para Atualizar um Atributo
Específico do Renderer
O Exemplo de Código 1-7 mostra como um desenvolvedor pode acessar atributos sem utilizar uma
superclasse específica de renderer. Os escritores de componentes podem introduzir também uma interface para
os métodos de atributos específicos de um renderer, implementados por cada subclasse específica de renderer.
Nota: Embora o JSF 1.1 mantenha o nome do estado da view em um campo hidden, o JSF 1.2
agora padronizou o nome como javax.faces.ViewState, de modo que mecanismos alterna-
tivos de postback, como Ajax, possam se integrar mais facilmente ao ciclo de vida do JSF.
<context param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context param>
Exemplo de Código 1-9. Associando um Renderer com uma Família de Componentes em Particular
<render-kit>
<renderer>
<component-family>
javax.faces.Input
</component-family>
<renderer-type>
com.apress.projsf.Date
</renderer-type>
<renderer-class>
com.apress.projsf.ch2.render.html.basic.HtmlInputDateRenderer
</renderer-class>
22 PRO JSF E AJAX
Nota: O prefixo javax.faces é reservado para uso das famílias de componentes definidas na
especificação JSF. Todos os exemplos neste livro utilizam o prefixo com.apress.projsf para
famílias customizadas de componentes.
O tipo de componente é um string utilizado para identificar a subclasse de UIComponent. Você pode
encontrar informação sobre o relacionamento entre o tipo de componente e a subclasse UIComponnete
no arquivo de configuração JSF, como mostrado no Exemplo de Código 1-10.
<component>
<component-type>
com.apress.projsf.ProInputDate
</component-type>
<component-class>
com.apress.projsf.ch2.component.pro.ProInputDate
</component-class>
O JSF também fornece um modo de associar listeners (classes que observam eventos) e transmitir
eventos para eles, semelhante à maneira como o AWT e Swing fazem. Por exemplo, um commandButton
é fonte para ActionEvents. Quando um commandButton é acionado, ocorre um postback (a página é enviada
para o servidor) e um novo ActionEvent é armazenado na fila de eventos. Quaisquer listeners de eventos
registrados com o commandButton serão notificados deste evento. O Exemplo de Código 1-12 mostra um
commandButton com um listener associado.
Nota: A especificação JSF para registrar listeners e transmitir eventos é baseada nos padrões de
projeto da especificação JavaBean 1.0.1.
<h:commandButton value=”Login”
action=”success”
actionListener=”#{sample.onLogin}” />
Facets
Uma view JSF é composta por uma hierarquia de componentes, permitindo acesso a cada filho de
componente por índice. Algumas vezes é necessário também fornecer um meio alternativo de adicionar
componentes subordinados que não são parte desta lista ordenada.
Um exemplo é o componente dataTable, onde os filhos representam as colunas a serem renderizadas
na tabela. Em alguns casos pode ser útil identificar um componente que represente o cabeçalho e/ou o rodapé
da tabela inteira, separado da coleção de filhos que representa as colunas individuais. Estes componentes filhos
header (cabeçalho) e footer (rodapé) são chamados de facets, referenciados apenas por nome e sem
ordenação específica. O nome de um facet representa o papel que o componente aninhado irá representar
no componente pai. É importante notar que um componente pai pode conter apenas um componente filho
com aquele nome de facet, mas o mesmo componente pai pode conter muitos componentes filhos indexados.
O Exemplo de Código 1-13 mostra como adicionar um facet header aos componentes dataTable
e column.
<h:column>
<f:facet name=”header” >
<h:outputText value=”Firstname” />
</f:facet>
<h:outputText value=”#{rows.firstname}” />
</h:column>
…
</h:dataTable>
Renderers
A especificação JSF delineia dois modelos de como um componente JSF pode lidar com valores advindos
de um request (decode - decodificar) ou enviados para uma resposta (encode - codificar). Estes dois modelos
– implementação direta ou implementação delegada –, tem duas abordagens distintas; a implementação direta
depende da instância do UIComponent para lidar com encode e decode, e a implementação delegada deixa
estas responsabilidades para um Renderer. Como você deve ter visto na Figura 1-5, a abordagem delegada
permite aos desenvolvedores de aplicação trabalhar diretamente com um UIComponent, independentemente
do que será renderizado no cliente. Neste livro vamos discutir apenas a abordagem de implementação delegada,
já que nosso objetivo é fornecer múltiplos Renderers para cada componente comportamental. Esta abordagem
é também o que torna o JSF um poderoso framework de UI.
Nota: A abordagem de implementação direta permite uma performance ligeiramente melhor, uma
vez que não há necessidade de delegar para um Renderer, mas também limita seriamente
a extensibilidade e portabilidade para vários clientes.
Os Renderers são responsáveis pela apresentação de um componente JSF e devem gerar o markup
apropriado para o client-side, como HTML e JavaScript ou XUL. Os Renderers também são responsáveis
por converter a informação oriunda do cliente para algo compreensível pelo componente (um string vindo
de um POST HTML para um objeto Date, por exemplo).
Embora um Renderer introduza atributos client-side, como: style, disabled, tootip e outros, estes
atributos são expostos na subclasse específica do renderer do componente (HtmlSelectOneRadio, por
exemplo).
Uma grande diferença entre UIComponents e Renderers é o modo que é definido em runtime.
Renderers são definidos como singletons, logo, existe apenas um Renderer para todas as instâncias de um
UIComponent para cada tipo de renderer em particular.
Cuidado: Já que instâncias individuais de Renderer serão criadas sob demanda durante o processo
de renderização e utilizadas durante o ciclo de vida da aplicação Web, é importante
entender que cada instância poderá ser invocada por mais de um thread de processamento
de requests simultaneamente. Isto requer que os Renderers sejam programados de
maneira thread-safe.
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 25
Renderer Types
O renderer type, ou tipo de renderer, é um identificador que é definido pelo componente e utilizado
em combinação com a família do componente; ele identifica univocamente qual classe Renderer deve ser
utilizada com o componente. Combinar renderer type com família de componentes é extremamente
poderoso já que permite o reuso do renderer type para múltiplos componentes comportamentais.
O Exemplo de Código 1-14 ilustra como uma família de componentes é associada com um renderer
específico e renderer type.
<render-kit>
<renderer>
<component-family>
javax.faces.Input
</component-family>
<renderer-type>
com.apress.projsf.Date
</renderer-type>
<renderer-class>
com.apress.projsf.ch2.renderer.html.HtmlInputDateRenderer
</renderer-class>
A Tabela 1-4 contém um subconjunto de famílias de componentes padrões com seus componentes
associados e renderer types.
Table 1-4. Um Subconjunto de Todas as Famílias de Componentes, seus Componentes e Renderer Types
Table 1-4. Um Subconjunto de Todas as Famílias de Componentes, seus Componentes e Renderer Types
(continuação)
A Tabela 1-4 mostra que o renderer type Text é utilizado em vários lugares – para o componente
HtmlInputText e para o componente HtmlOutputText. A combinação da família de componentes Output
e o renderer type Link utiliza a classe de Renderer que irá gerar um elemento HTML link – <a
href=”...”>texto</a> – para o cliente.
RenderKits
A funcionalidade do RenderKit é suportar UIComponents que utilizem a abordagem de implementação
delegada com a delegação de Renderers para o UIComponent. Os RenderKits agregam instâncias de
Renderers com tipos de markup similares, e o RenderKit default fornecido por todas as implementações
JSF é o RenderKit básico de HTML, contendo Renderers que produzem saída HTML 4.0.1. Outros
RenderKits possíveis podem possuir Renderers suportando tecnologias de exibição como SVG, WML,
Ajax, XUL e outras. Neste livro você verá RenderKits adicionais para Componentes DHTML/HTML da
Microsoft e para a linguagem de associação XUL/XML do Mozilla (XBL).
O RenderKit não é responsável por criar o Renderer porque armazena apenas uma única instância
de cada renderer type. Cada RenderKit é associado com uma view (hierarquia de componentes) em runtime
com a propriedate UIViewRoot. Se nenhum RenderKit foi selecionado, o RenderKit default irá ser
utilizado. Em se tratando de RenderKits, muitas vezes não haverá necessidade de criar um novo
RenderKit. Adicionar um Renderer customizado a um RenderKit pré existente é apenas uma
operação de configuração. Se um identificador de RenderKit for omitido, o Renderer customizado será
automaticamente adicionado ao RenderKit de HTML default. Se quiser adicionar um RenderKit com
Renderers customizados, você pode fazer a mesma coisa - atualizar o arquivo de configuração JSF. O
Exemplo de Código 1-15 mostra como adicionar um novo Renderer ao arquivo de configuração JSF.
<render-kit>
<!— no render-kit-id, so add this Renderer to the HTML_BASIC RenderKit —>
<renderer>
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 27
<component-family>
javax.faces.Input
</component-family>
<renderer-type>
com.apress..projsf.Date
</renderer-type>
<renderer-class>
com.apress.projsf.ch2.renderer.html.HtmlInputDateRenderer
</renderer-class>
...
</render-kit>
A estrutura da página é simples e descreve uma página contendo dois campos de entrada para username
e password e um botão para efetuar o login. A Figura 1-9 mostra como a página se parece quando renderizada
no browser.
A segunda página da aplicação, mostrada no Exemplo de Código 1-17, é simples e meramente ilustra
a navegação e totalidade do ciclo de vida. A página contém um componente <h:outputText> que renderizará
o valor digitado no componente <h:inputText> para o username na página inicial, em caso de login bem
sucedido.
<body>
<h:form>
<h:outputText value=”#{credentials.username}” />
</h:form>
</body>
</html>
</f:view>
</jsp:root>
Para poder navegar de uma página para outra, você tem que definir um navigation case (caso de
navegação) no arquivo de configuração do JSF – faces-config.xml. Também necessita criar um
mapeamento para o código de backend utilizando um managed bean. O Exemplo de Código 1-18 mostra
como fazer isto.
<navigation-rule>
<from-view-id>/login.jspx</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/result.jspx</to-view-id>
</navigation-case>
</navigation-rule>
<managed-bean>
<managed-bean-name>credentials</managed-bean-name>
<managed-bean-class>
com.apress.projsf.ch1.application.CredentialsBean
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
Como pode ver, o Exemplo de Código 1-18 define que, a partir da página login.jspx, no caso de sucesso,
o usuário da aplicação será direcionado para a página result.jspx. Ela também define um managed bean
que aponta para uma classe –CredentialsBean –, contendo uma lógica de aplicação simples. O Exemplo
de Código 1-19 mostra a lógica de aplicação.
package com.apress.projsf.ch1.application;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
{
If (!”duke”.equalsIgnoreCase(_username))
throw new AbortProcessingException(“Unrecognized username!”);
// clear out the password, for good measure!
_password = null;
}
public void setUsername(
String username)
{
_username = username;
}
public String getUsername()
{
return _username;
}
public void setPassword(
String password)
{
_password = password;
}
public String getPassword()
{
return _password;
}
private String _username;
private String _password;
}
Cada aplicação Web JSF tem uma ApplicationFactory. Esta classe de factory é responsável por criar
e substituir a instância da classe Application necessária para todas as aplicações que utilizam JSF. A
instância de Application fornecer serviços suportados pela instância a outros processos. Semelhantemente,
o arquivo de configuração JSF – faces-config.xml – é lido uma só vez durante a criação da aplicação Web
e armazenado na instância de Application.
A RenderKitFactory é responsável por retornar uma instância de RenderKit baseada no
identificador de RenderKit para esta aplicação Web JSF. Para cada implementação JSF deve haver
um RenderKit default – o RenderKit HTML, que é identificado por uma constante string –
RenderKitFactory.HTML_BASIC_RENDER_KIT. A LifecycleFactory é responsável por criar (se
necessário) e retornar uma instância de Lifecycle. Esta instância de Lifecycle é responsável por invocar
a lógica de processamento para implementar a funcionalidade desejada para cada fase (veja a Figura 1-8)
do ciclo de vida de processamento de requests. A última factory – FacesContextFactory –, fornece à
implementação JSF uma maneira de criar instância de FacesContext, utilizada para representar informação
contextual associada com um request e, eventualmente, criando uma resposta.
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 33
Request Inicial
Quando o usuário acessa a aplicação pela primeira vez, um request inicial é enviado ao FacesServlet,
o qual despacha o request para a instância de Lifecycle JSF (veja a Figura 1-10).
Na figura 1-11, você está observando o processo de um request inicial e como a primeira fase – Restore
View – no ciclo de vida JSF é responsável por restaurar uma view do servidor e o estado do cliente. Durante
o primeiro request para esta view, o método ViewHandler.restoreView() retornará null, já que não há estado
armazenado.
Nota: Os identificadores de fase de ciclo de vida JSF são parte da API pública do JSF na classe
PhaseId.
34 PRO JSF E AJAX
Se o valor de retorno é null, a fase Restore View chamará renderResponse() no FacesContext para este
request. O método renderResponse() indicará que quando esta fase estiver concluída, o método render()
será chamado para executar a fase 6 – Render Response – sem passar pelas fases 2 até 5. Subseqüentemente,
a fase Restore View irá chamar o método ViewHandler.createView() para criar a raiz da hierarquia de
componentes – UIViewRoot – e anexá-la ao FacesContext. O componente UIViewRoot não renderiza
nada, mas executa um papel importante na distribuição de eventos durante um request postback
(secundário).
Durante esta fase, o método ViewHandler.renderView() é chamado para executar o documento JSP.
O método renderView() passará o valor da propriedade viewId adquirido do nó UIViewRoot, como um
path relativo ao contexto para o método dispatch()do ExternalContext associado a este request. O método
dispatch() irá encaminhar o valor da propriedade viewId (“/login.jspx” como um path relativo ao contexto,
por exemplo) para o container Web.
Já que o mapeamento específico do JSF não é parte do request encaminhado; o request será ignorado
pelo FacesServlet e passado diretamente ao container JSP, o qual, por sua vez, localizará o JSP baseado
no path relativo ao contexto e executará a página JSP correspondente ao viewId (“/login.jspx”, por
exemplo). A Figura 1-13 mostra o processamento de um documento JSF JSP.
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 35
Antes de processar e executar o documento JSF JSP, o runtime do JSP determina primeiramente o
tipo de conteúdo e encoding de caracteres a ser utilizado. Para o JSF trabalhar em harmonia com o ciclo
de vida JSP, o tag <f:view> necessita estar presente. O tag <f:view> é um tag JSP body que armazena
(em buffer) todo o conteúdo renderizado pelos componentes JSF aninhados. Simplesmente falando, o tag
<f:view> serve como um container para todos os outros componentes JSF. O tag <f:view> é responsável
por criar e armazenar uma instância de ResponseWriter no FacesContext.
O método createResponseWriter() cria uma nova instância de ResponseWriter para o tipo de conteúdo
e encoding específicos. O ResponseWriter é responsável por escrever o markup gerado para o cliente, neste
caso para o buffer de conteúdo do <f:view>.
36 PRO JSF E AJAX
Para cada tag JSF JSP dentro do <f:view> um componente JSF é criado e anexado à hierarquia de
componentes durante o request inicial. Como deve-se lembrar, o UIViewRoot é criado na primeira fase
e anexado ao FacesContext, de modo que podemos seguramente assumir que os componentes serão
anexados à hierarquia de componentes. A Figura 1-14 mostra a execução do tag inicial <h:form>.
No documento JSP login, o próximo tag JSF JSP a ser executado é o <h:form>. O tag JSF JSP invoca
o método Application.createComponent() que recebe um string representando o tipo de componente, por
exemplo: “javax.faces.HtmlForm” (veja a seção “Famílas de Componentes e Tipos de Componentes”).
O tipo de componente é mapeado a uma classe definida no arquivo faces-config.xml, e uma instância do
componente HtmlForm é criada e anexada ao UIViewRoot. A seguir, um Renderer para o componente
recém-criado necessita ser encontrado. Um Renderer é localizado pela família de componentes e Renderer
Type, os quais juntos definem um identificador único para o Renderer (veja a seção “Renderer Types”).
Nota: Vamos usar o componente HtmlInputText para ilustrar o relacionamento entre a família
de componentes e o renderer type. O componente HtmlInputText tem a família
“javax.faces.Input” e o renderer type “javax.faces.Text”. Juntos, eles identificam unicamen-
te a classe apropriada de Renderer dentro do RenderKit básico HTML –
javax.faces.renderer.html.HtmlInputText.
O renderer type já é conhecido pelo tag <h:form>, e a família de componentes pode ser localizada na
superclasse do componente, UIForm. O tag, então, chama um método endcodeBegin() no componente,
o qual, por sua vez, chama o método encodeBegin() no renderer do HtmlForm. O método encodeBegin()
no Renderer chama métodos no ResponseWriter para escrever o markup para o elemento HTML form -
<form method=”” action=””>. Toda a saída do ResponseWriter é enviada para o buffer de conteúdo do
<f:view>. A Figura 1-15 mostra o processo de fechamento do tag <h:form>.
Nota: O ViewHandler representa a tecnologia de view e, neste caso, a tecnologia de view é JSP.
Nada na especificação JSF previne qualquer um de implementar um ViewHandler
alternativo para outra tecnologia de view, como XML.
No momento que pegar o tag de fechamento </f:view>, toda a hierarquia de componentes está
disponível. Você não pode salvar o estado da hierarquia de componentes representando esta página da
aplicação até ter a árvore completa. O tag </f:view> chama o método writeState() no StateManager.
Dependendo do parâmetro inicial – STATE_SAVING_METHOD – para a preservação do estado (veja
a seção “Salvando e Restaurando o Estado”), o StateManager armazena o estado na sessão no servidor
ou delega ao ResponseStateManager a tarefa de salvar o estado no cliente, substituindo o token com o estado
serializado. Após o estado ter sido salvo, o buffer é enviado ao cliente e a execução de qualquer tag JSP
(não JSF) será efetuada. A página de login é agora renderizada no browser.
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 39
Note: No JSF 1.2, o tag <f:view> não é mais responsável por armazenar a saída em buffer. Ao invés
disto, o armazenamento é feito utilizando um wrapper (padrão decorator) para
ServletResponse. Adicionalmente, a hierarquia de componentes não é mais criada durante
a renderização. Durante a fase Render Response do JSF 1.2, a hierarquia é criada primeiro
e renderizada depois. Logo, durante a renderização, a hierarquia completa está disponível,
logo, o estado é gravado diretamente na resposta armazenada, ao invés de necessitar um
token para ser substituído pelo estado real no </f:view>.
Request Postback
Até agora, a única coisa que o usuário viu foi a renderização inicial da primeira página requisitada. Após
receber a página, o usuário digita o username, a password e clica no botão de login. Um postback é efetuado
e veremos agora como o JSF lida com postbacks. Algumas partes são similares ao que estivemos falando
no request inicial, mas existem, obviamente, diferenças, especialmente no ciclo de vida de request JSF.
No postback, todas as seis fases do ciclo de vida de request JSF são chamadas (a não ser que em algum
lugar do processo o método FacesContext.renderResponse() seja chamado, forçando o ciclo de vida a pular
diretamente para a fase Render Response). Isto é diferente do request inicial, onde apenas a primeira e última
fases eram chamadas.
Aqui é onde as semelhanças terminam; ao invés de retornar null, o método restoreView() retornará
o estado corrente da hierarquia de componentes associada com um viewId e FacesContext do StateManager
e se o parâmetro inicial – STATE_SAVING_METHOD – for selecionado para client-side, chamará o
ResponseStateManager para recuperar o estado do request corrente. A hierarquia de componentes é então
passada para o FacesContext pela fase Restore View.
O valor submetido neste ponto é armazenado como “submitted” (submetido) no componente e nenhum
valor foi colocado no modelo ainda. No momento em que a fase Apply Request for completada, os
Renderers não mais necessitam observar os parâmetros de request, já que todos os valores foram
atualizados em cada componente.
Como mencionado na seção anterior “Converters, Validators, Events e Listeners”, temos dois métodos
que serão processados quando ocorrer um ActionEvent. A primeira coisa que acontece é uma chamada
ao método processApplication(), no UIViewRoot, que recebe cada evento enfileirado e transmite para o
componente alvo para o evento (por exemplo: “commandButton.broadcast(FacesEvent)”). O componente
UICommand sabe sobre os atributos action e actionListener, assim como o default ActionListener anexado
ao objeto Application.
Primeiramente, todos os ActionListeners registrados são chamados e, então, a associação de método
actionListener é executada (por exemplo: “#{credentials.onLogin}”), e, finalmente, o componente chama
o método processAction() no ActionListener default para processar o método de ação e lidar com a
navegação. É importante que a associação de método de ação seja chamada no final do processo, já que
ela define uma possível navegação e não queremos navegar antes de processar todos os eventos.
Durante um postback, a primeira parte da fase Render Response é a mesma que no request inicial até
a chamada do método dispatch(), exceto que temos agora uma hierarquia de componentes completa e não
apenas o UIViewRoot (veja a Figura 1-13). Após despachar, a página JSP é executada e o tag inicial
<f:view> faz a mesma coisa que no request inicial – criar e armazenar uma instância do ResponseWriter
no FacesContext e atuar como um buffer para a saída renderizada dos componentes (veja a Figura 1-14).
Ao invés de criar novos componentes e anexá-los ao UIViewRoot, como no request inicial, as tags
de componentes individuais aninhadas dentro do tag <f:view> terão que localizar suas contrapartidas que
já existam na hierarquia de componentes. Isto acontece durante a execução da página JSP, atravessando
até o início da árvore de tags para encontrar o tag de componente pai mais próximo. A partir do tag do
componente pai, o tag do componente filho pode encontrar seus componentes correspondentes pelo
identificador de componente ou pelo nome do facet (veja a seção “Facets”).
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 45
JSF e JSP
No JSF, um criador de componentes pode alterar uma propriedade booleana, chamada rendersChildren,
em um componente. Esta propriedade decide se um componente deve ou não renderizar seus componentes-
filhos. Para componentes da implementação JSF, o valor de rendersChildren é sempre false. Isto significa
que cada componente é responsável por renderizar sua saída para o ResponseWriter e armazená-la no buffer
de <f:view>, não importando como seus filhos são renderizados. Se rendersChildren for alterada para true
em um componente, então o método encodeBegin() é chamado no tag de fechamento ao invés de no tag
de inicialização (veja a Figura 1-14) para assegurar que nenhum filho é renderizado para o buffer até que
o pai termine o loop em seus filhos. Uma vez que o pai sabe sobre seus filhos, eles podem ser renderizados
no buffer de conteúdo do <f:view>. Um componente que usa isto é o dataTable, porque necessita ter acesso
a todos os seus componentes-filhos antes que qualquer saída seja renderizada.
Considerando que alguns componentes possam requerer que rendersChildren seja true, haverá impacto
na maneira como você constrói sua descrição de página. Lembra-se da página de Login? Vamos adicionar
alguns rótulos aos campos de entrada e ajustar um pouco o layout, de modo que os componentes fiquem
alinhados verticalmente, ao invés de horizontalmente, como mostrado no Exemplo de Código 1-20.
Exemplo de Código 1-20. A Página Login Modificada com Alguns Tags JSP
<jsp:text>Username</jsp:text>
<h:inputText value=”#{sample.username}” />
<jsp:text>Password</jsp:text>
<h:inputText value=”#{sample.password}” />
</h:panelGrid>
<h:commandButton value=”Submit” action=”#{credentials.onLogin}” />
46 PRO JSF E AJAX
</h:form>
</body>
</html>
</f:view>
</jsp:root>
Este exemplo insere os componentes em um tag <h:panelGrid>. O componente criado por este tag
renderiza seus filhos em um grid bi-dimensional, com duas colunas. O componente HtmlPanelGrid tem
sua propriedade rendersChildren como true, logo, ele pode observar todos os seus filhos antes de renderizar
o markup para cada coluna. O exemplo também adiciona dois tags que não são JSF –<jsp:text>– que
adicionarão um rótulo a cada campo de entrada. Em runtime a página se parece com a Figura 1-24.
Como pode ver, os rótulos Username e Password fora colocados incorretamente no topo da página.
Durante a execução desta página, qualquer componente JSF dentro do componente HtmlPanelGrid será
proibido de ser renderizado até que o tag final de HtmlPanelGrid (“</h:panelGrid>”) seja lido. Note que
nenhum tag ou texto arbitrário aninhado dentro do componente HtmlPanelGrid será adiado. Logo,
<jsp:text> é renderizado para o buffer imediatamente. Você pode alterar este comportamento colocando
um tag <f:verbatim> em volta do conteúdo JSF, como no Exemplo de Código 1-21.
Exemplo de Código 1-21. A Página Login com o Tag <f:verbatim> em Volta do Conteúdo que Não é JSF
<h:form>
<h:outputText value=”Application Login”/>
<h:panelGrid columns=”2">
<f:verbatim><jsp:text>Username</jsp:text></f:verbatim>
<h:inputText value=”#{credentials.username}” />
<f:verbatim><jsp:text>Password</jsp:text></f:verbatim>
<h:inputText value=”#{credentials.password}” />
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 47
</h:panelGrid>
<h:commandButton value=”Submit” action=”#{credentials.onLogin}” />
</h:form>
O tag <f:verbatim> pega o conteúdo que não é JSF e o adiciona à hierarquia de componentes como
um componente UIOutput. Em runtime, a página se parecerá com a Figura 1-25.
Nota: O problema com o rendersChildren foi resolvido pelo JSF Expert Group na versão JSF 1.2.
A nova característica de intercalação de conteúdo (content-interweaving) acomoda as
diferenças entre as estratégias de renderização do JSP e JSF, tornando desnecessário
adicionar o tag <f:verbatim>.
RESUMO
Este capítulo age como um mini guia para o resto do livro; ele também lhe dá a fundamentação para
continuar sua jornada dentro do mundo do JSF além deste livro.
Uma dos diferenciais-chave do JSF sobre as outras tecnologias de view é sua abertura e
habilidade de adoção de tecnologias emergentes, como XUL, HTC e Ajax, assim como outras
tecnologias de view futuras. O JSF tem benefícios claros sobre outras tecnologias porque uma
aplicação criada com ele pode continuar a viver enquanto as tecnologias em torno se vão e outras
nascem. O JSF pode reduzir os custos de manutenção do desenvolvimento de aplicação, já que
apenas um único modelo de programação é necessário – JSF e Java – mesmo que os sistemas
necessitem de agentes diferentes, como Telnet, mensagem instantânea, PDAs, browsers e outros
tipos como leitores de código de barras.
Este capítulo tratou de detalhes que compõem uma aplicação JSF – os componentes, modelo de
navegação e lógica através de managed beans. Também exploramos os prós e contras do modelo de
componentes JSF e sua clara separação entre apresentação e comportamento, além de discutirmos a
estrutura dos componentes JSF – UIComponent, Renderer, subclasse específica RenderKit e o processador
48 PRO JSF E AJAX
de tags JSP. O capítulo também detalhou como o ciclo de vida de request do JSF funciona no request inicial
e no postback, incluindo a navegação.
É crucial entender a separação entre apresentação e comportamento de modo a compreender o potencial
dos componentes JSF.