Você está na página 1de 48

PARTE 1

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.

Tabela 1-1. Tipos de desenvolvedores JSF*

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

Tabela 1-1. Tipos de desenvolvedores JSF* (continuação)

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

* Fonte: a especificação 1.1 do JavaServer Faces.

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.

RESUMO DAS TECNOLOGIAS


DE DESENVOLVIMENTO DE APLICAÇÕES
Ao longo de relativamente curta história dos computadores e do software, o desenvolvimento de
aplicações passou por várias grandes etapas evolucionárias, todas prometendo aumentar a produtividade
e a flexibilidade do desenvolvedor. Estas melhorias tecnológicas progrediram exponencialmente desde
que o primeiro computador foi introduzido, e parece que as tecnologias de computadores e software
continuarão a evoluir no mesmo ritmo acelerado no futuro.

Nenhum exponencial é eterno... mas podemos adiar o “eterno.”


– Gordon Moore (famoso pela lei de Moore)
Fairchild Camera and Instrument Corporation

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.

One-Tier (Um Tier)


No final dos anos 70 e começo dos anos 80, ocorreu um deslocamento fundamental dos grandes
computadores centrais para os computadores pessoais (Personal Computers ou PCs), o qual moveu o poder
de controle de umas poucas pessoas para muitas pessoas (qualquer um com um PC). Embora a maioria das
aplicações entregue neste período fosse mais poderosa do que qualquer coisa desenvolvida até então, ela era
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 5

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.

Multitier: Aplicações Web


A próxima fase no desenvolvimento de aplicações chegou com a Internet e o Web browser,
introduzindo a arquitetura three-tier ou multitier. Na solução one-tier, as lógicas de apresentação, negócios
e dados são integradas em uma aplicação monolítica. A arquitetura multitier quebra este tipo de aplicação
em três camadas, permitindo aos desenvolvedores se focalizarem em áreas de domínio específico – model
(ou modelo – acesso aos dados), view (ou visão – apresentação) e controller (ou controlador – lógica).
Este paradigma de programação, representando a divisão entre estas camadas, é conhecido como a
arquitetura Model-View-Controller (MVC) e foi primeiramente introduzida pela linguagem SmallTalk,
espalhando-se pela comunidade de desenvolvedores nos anos 80.
Dividir uma aplicação monolítica em camadas – em combinação com um cliente padronizado (um Web
browser, por exemplo) e um protocolo padronizado de comunicação (Hypertext Transfer Protocol [http])
– repentinamente deu aos usuários acesso ubíquo (onipresente) às aplicações centralizadas e familiares, como
email via browser (Gmail do Google, por exemplo). As aplicações não são mais algo que somente poderiam
vir em um CD ou através de um download. Uma solução multitier dá ao proprietário da aplicação administração
e manutenção centralizadas, o que lhe permite atualizações instantâneas para todos que a utilizem.

EXPLORANDO O DESENVOLVIMENTO DE APLICAÇÕES ATUAL


Neste novo mundo de aplicações multitier, os desenvolvedores necessitam estar atualizados com as
tecnologias e padrões emergentes, fornecidos através de organizações como o World Wide Web
Consortium (W3C) e o Java Community Process (JCP). A indústria está em evolução, o que é bom, mas
6 PRO JSF E AJAX

também pressiona os desenvolvedores de aplicações a sempre construírem aplicações multitier competi-


tivas. Se observar uma solução de software multitier típica – servindo uma empresa de varejo, por exemplo
–, verá que ela poderá incluir suporte a múltiplos agentes, como Web browsers, dispositivos móveis
(PDAs) e terminais de vídeo baseados em caracteres (VT, por exemplo o VT100).
A figura 1-1 mostra um esquema simples da arquitetura de tal aplicação multitier.

Figura 1-1. Arquitetura comum J2EE para uma soluÁ„o


tÌpica multitier servindo uma empresa de varejo.

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.

Tapestry, Struts, Tiles, TopLink, Hibernate, ADF UIX


Muitos frameworks possuem as mesmas idéias, mas resolvem um problema de maneira diferente e
em diferentes camadas de uma aplicação multitier (camada view, camada controller e camada model). Como
exemplos de frameworks, temos Struts (um framework controlado por open source); TopLink e Hibernate
(frameworks da camada model); Tiles, Tapestry, XUL e ADF UIX (frameworks da camada view).
Os benefícios dos frameworks de aplicação são: modularidade, reusabilidade e a inversão de controle
(Inversion of Control - IoC), que eles fornecem aos desenvolvedores. Ao encapsular os detalhes de
implementação, os frameworks aumentam a modularidade e melhoram a qualidade do software através
da centralização do impacto dos detalhes de projeto e implementação. Graças ao ambiente estável criado
pelos frameworks, estes benefícios aumentam o reuso ao permitir que os desenvolvedores criem
componentes genéricos que podem ser reutilizados em novas aplicações. Esta reutilização de componentes
de framework aumenta a produtividade do desenvolvedor e a qualidade do software da aplicação. Ao
promover o IoC, o framework gerencia a chamada dos métodos específicos da aplicação em resposta aos
eventos gerados pelo usuários.

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

Exemplo de Código 1-1. Regras de Navegação Configuradas no faces-config.xml.

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

Ciclo de Vida de Aplicação


Outro benefício que os desenvolvedores de aplicação irão descobrir quando utilizarem JSF é que o
framework auxilia a gerenciar o estado da UI através dos requisitos ao servidor. Ao invés de tomar conta
das seleções feitas pelo usuário e passá-las de página em página, o framework cuidará disto para você.
O framework JSF também possui processos intrínsecos em seu ciclo de vida para lhe auxiliar com a
validação, conversão e atualização dos modelos. Como um bônus extra, o JSF fornece um modelo simples
para enviar eventos gerados pelo cliente para o código de aplicação no servidor.

Desenvolvimento de Aplicações com o JSF


Um dos diferencias chave do JSF é sua arquitetura, projetada para ser independente de protocolos
específicos e de código, de tal forma que permite aos desenvolvedores anexarem qualquer tecnologia de
renderização à aplicação JSF. No JSF o RenderKit é o responsável pela apresentação da aplicação JSF,
renderizando o código para o cliente. Você pode definir um RenderKit para qualquer tipo de código (HTML,
DHTML, Telnet/modo caracter, e, eventualmente, SVG, Flash, XUL etc) e utilizá-lo para exibir uma página
JSF.
Esta separação entre a descrição da página (hierarquia de componentes UI) e a renderização do código
é um diferencial-chave que resulta em flexibilidade para o desenvolvedor de componentes, enquanto
protege o desenvolvedor de aplicação das mudanças isoladas na camada de renderização. Ao invés de ter
que aprender e implementar as diferentes tecnologias de renderização para resolver um problema comum,
os desenvolvedores de aplicação podem utilizar componentes customizados JSF para criar aplicações
voltadas para diferentes browsers, assistentes pessoais (PDAs) e outros, com um modelo de programação
comum: JSF e Java.
Aplicando este novo conhecimento sobre JSF no exemplo prévio da figura 1-1, a solução de varejo,
a arquitetura poderia ser similar à figura 1-2.
10 PRO JSF E AJAX

Figura 1-2. A arquitetura J2EE utilizando JSF para uma


soluÁ„o multitier tÌpica, servindo uma empresa de varejo.

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

Figura 1-3. Uma arquitetura MVC com JSF (Model 2).

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.

Exemplo de Código 1-2. 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.

Tabela 1-2. Escopos de Managed Beans

Escopo de Managed Bean Descrição


None A instância será criada para cada chamada do método
Request A instância será criada para cada novo request
Session A instância será criada no request inicial e armazenada na sessão do usuário
Application A instância será criada no request inicial e armazenada na aplicação Web

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.

Figura 1-4. Da descriÁ„o da p gina ‡ hierarquia de componentes JSF.

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.

Um Framework de Interface de Usuário Baseado em Componentes


Agora que já arrumamos o palco para o livro, é hora de focalizarmos nas partes que diferenciam o JSF
de outras tecnologias antigas: UIComponents. O JSF é um framework baseado em componentes UI, no
qual componentes, como HtmlDataTable e HtmlPanelGrid, podem ser visualizados como blocos pré-
fabricados que permitem aos desenvolvedores de aplicação produtivamente construir aplicações comple-
xas com componentes reutilizáveis. Ele também permite aos desenvolvedores de aplicação focalizarem na
lógica da aplicação, ao invés da criação de funcionalidades ricas e dinâmicas.

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.

O JSF consiste de cinco blocos fundamentais:


• UIComponent: O UIComponent é responsável pelo comportamento e por acessar o modelo de
dados.
• Renderer: O Renderer está a cargo de apresentar o código de markup para o cliente para uma família
de componentes.
• RenderKit: É uma biblioteca de Renderers com uma tecnologia comum de renderização (HTML,
por exemplo).
• Subclasse de componente específica para um renderer: A subclasse de componente específica
para um renderer é uma classe de conveniência e representa facetas e atributos específicos para
um renderer.
• Tag JSP: A linguagem de descrição de páginas default do JSF é o JSP, logo, o JSF necessita
seguir o contrato do JSP e fornecer tags JSP representando cada componente JSF.
O JSF endereça a idéia de separação clara entre a lógica de aplicação e a apresentação visual através
de uma separação forte da UI e do modelo de dados. O Renderer é o responsável pelo código markup
renderizado para o cliente e o UIComponent é o responsável pelo comportamento e por acessar o modelo
de dados. A figura 1-5 mostra a separação da UI, comportamento e modelo de dados.
14 PRO JSF E AJAX

Figura 1-5. SeparaÁ„o da UI, do comportamento e do modelo de dados.

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.

Figura 1-6. O UISelectOne e seus renderers.


CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 15

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.

Tabela 1.3. Componentes Fornecidos pela Implementação JSF*.

UI Component Renderer-Specific Class Renderer Type Syntax/JSP Tag


UIColumn null** <h:column>
UICommand HtmlCommandButton Button <h:commandButton>
HtmlCommandLink Link <h:commandLink>
UIData HtmlDataTable Table <h:dataTable>
UIForm HtmlForm Form <h:form>
UIGraphic HtmlGraphicImage Image <h:graphicImage>
UIInput HtmlInputHidden Hidden <h:inputHidden>
HtmlInputSecret Secret <h:inputSecret>
HtmlInputText Text <h:inputText>
HtmlInputTextArea Textarea <h:inputTextarea>
UIMessage HtmlMessage Message <h:message>
UIMessages HtmlMessages Messages <h:messages>
UIOutput HtmlOutputFormat Format <h:outputFormat>
HtmlOutputLabel Label <h:outputLabel>
Continuação
16 PRO JSF E AJAX

Tabela 1.3. Componentes Fornecidos pela Implementação JSF*. (continuação)

UI Component Renderer-Specific Class Renderer Type Syntax/JSP Tag


HtmlOutputLink Link <h:outputLink>
HtmlOutputText Text <h:outputText>
UIPanel HtmlPanelGrid Grid <h:panelGrid>
HtmlPanelGroup Group <h:panelGroup>
UIParameter null* <h:parameter>
UISelectOneBoolean HtmlSelectBooleanCheckbox Checkbox <h:selectBooleanCheckbox>
UISelectItem null <h:selectItem>
UISelectItems null <h:selectItems>
UISelectMany HtmlSelectManyCheckbox Checkbox <h:selectManyCheckbox>
HtmlSelectManyListbox Listbox <h:selectManyListbox>
HtmlSelectManyMenu Menu <h:selectManyMenu>
UISelectOne HtmlSelectOneListbox Listbox <h:selectOneListbox>
HtmlSelectOneMenu Menu <h:selectOneMenu>
HtmlSelectOneRadio Radio <h:selectOneRadio>
UIViewRoot null <f.view>
* Fonte:Especificação do JavaServer Faces 1.1
** Este componente não possui um renderer associado.

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.

Subclasse de Componente Específica para um Renderer


Na maioria dos casos, esta subclasse cria uma instância do componente em runtime. Como seu nome
diz, esta subclasse permite acesso aos atributos específicos do renderer em um componente JSF, como: style,
disabled, tooltip e outros, fornecendo getters e setters de propriedades para todos estes atributos. Em conjunto
com o atributo binding no tag JSP do JSF, esta subclasse permite aos desenvolvedores de aplicação usar setters
de propriedade JavaBean para alterar atributos específicos do renderer no componente em runtime.
Embora isto funcione e seja uma ferramenta útil para prototipagem, nós recomendamos que, quando
possível, os desenvolvedores de aplicação evitem modificar os atributos específicos do renderer a partir
da lógica de aplicação do backing bean, utilizando, ao invés disto, as superclasses comportamentais do
componente. Se os desenvolvedores de aplicação utilizarem a classe ancestral ao invés da classe de
conveniência, eles não necessitarão modificar o código do backing bean quando o componente JSF for
alterado para utilizar um componente específico de renderer, diferente na definição da página, como mudar
de HtmlSelectOneRadio para HtmlSelectOneListbox. O código do backing bean somente necessita ser
alterado quando a superclasse comportamental é também alterada, como mudar de HtmlSelectOneRadio
para HtmlSelectManyList.
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 17

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.

Figura 1-7. A heranÁa de UIComponent.

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.

Utilizando uma Subclasse Específica de Renderer


O Exemplo de Código 1-3 ilustra o benefício de utilizar uma superclasse comportamental ao invés da
classe de conveniência para manipular a página em runtime. O primeiro pedaço do código ilustra uma página
com um componente selectOneRadio simples com três opções e um commandButton.

Exemplo de Código 1-3. Um JSF selectOneRadio Ligado a umaSsubclasseEespecífica de Renderer.

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

Exemplo de Código 1-4. Um Backing Bean Utilizando a Subclasse HtmlSelectOneRadio

package com.apress.projsf.ch1.application;

import javax.faces.event.ActionEvent;
import javax.faces.component.html.HtmlSelectOneRadio;

public class SampleBean


{
public void onAction(
ActionEvent event)
{
_selectOneRadio.setValue(“java.dude”);
}

public void setSelectOneRadio(


HtmlSelectOneRadio selectOneRadio)
{
_selectOneRadio = selectOneRadio;
}

public HtmlSelectOneRadio getSelectOneRadio()


{
return _selectOneRadio;
}

private HtmlSelectOneRadio _selectOneRadio;


}

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

Exemplo de Código 1-5. Um JSF selectOneRadio Ligado a uma Superclasse Comportamental

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

Exemplo de Código 1-6. O Novo Backing Bean Utilizando a classe UISelectOne.

package com.apress.projsf.ch1.application;

import javax.faces.event.ActionEvent;
import javax.faces.component.UISelectOne;

public class SampleBean


{
public void onAction(
ActionEvent event)
{
_selectOne.setValue(“java.dude”);
}

public void setSelectOne(


UISelectOne selectOne)
{
_selectOne = selectOne;
}

public UISelectOne getSelectOne()


{
return _selectOne;
}

private UISelectOne _selectOne;


}
20 PRO JSF E AJAX

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.

Acessando Atributos Específicos do Renderer


No exemplo anterior, nós alteramos programadamente a propriedade value no componente UISelectOne,
a qual é definida pela superclasse comportamental. Mas como um desenvolvedor de aplicação tem acesso
aos atributos específicos do renderer, se a subclasse específica dele não foi fornecida ou (como no Exemplo
de Código 1-6) não foi utilizada? Todos os atributos e propriedades são acessados por um Map centralizado
que pode ser utilizado a partir de qualquer clase UIComponent e subclasses, através de uma propriedade
chamada attributes, como mostrado no Exemplo de Código 1-7.

Exemplo de Código 1-7. Utilizando o Mapa de Atributos de Componente para Atualizar um Atributo
Específico do Renderer

// Renderer-specific attribute example


Map attrs = selectOne.getAttributes();
attrs.put(“style”, “font-face:bold”);

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.

Salvando e Recuperando o Estado


Uma parte crucial da criação de aplicações Web é salvar estado. Pegue um carrinho de compras
tradicional, baseado em HTML, como exemplo. Neste caso, o desenvolvedor de aplicação tem que
armazenar as seleções de produto do usuário e persistir esta informação até que ele finalize a compra. Na
maioria dos casos, uma aplicação de carrinho de compras é criada com múltiplas páginas, de modo que
o estado de cada página deve ser salvo até que o comprador finalize a compra. Este estado é armazenado
em campos hidden dentro de formulário, armazenada na sessão ou passada como request para a próxima
página. Aqueles que já lidaram com isto sabem que não é uma tarefa trivial.
O gerenciamento de estado é um dos benefícios primários do uso de JSF para criar aplicações. O JSF
fornece manuseio de estado de UI automático através de uma classe chamada StateManager, que salva
e recupera o estado para uma view em particular (hierarquia dos UIComponents) entre requests no
servidor. Cada UIComponent salva e recupera seu próprio estado interno quando requisitado pelo
StateManager; o StateManager por si salva e recupera o estado associado com a estrutura da
hierarquia do UIComponent. Se um UIComponent estiver marcado como transient, então será
omitido da estrutura pelo StateManager, sendo removido da árvore UIComponent ao final do request.
Existem duas alternativas para armazenar o estado de uma view – no lado cliente ou no lado servidor.
Por default, o estado é salvo no servidor. A implementação Server-side (lado do servidor) é suportada pelas
especificações JSP e Servlet, mas o JSF lida com os detalhes de como isto funciona. Uma classe chamada
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 21

ResponseStateManager, a qual é criada e gerenciada pelo RenderKit, gerencia a preservação de


estado do lado cliente (client-side). A preservação de estado client-side depende não apenas da
implementação JSF, mas também muito da linguagem de marcação enviada para o cliente e como o estado
pode ser gerenciado por ele. Usando HTML como linguagem de marcação, o estado é armazenado
tipicamente em um campo hidden de formulário.

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.

Uma das desvantagens de salvar o estado na sessão do usuário é o consumo de memória. Se a


escalabilidade é um problema para os desenvolvedores de aplicação, a implementação client-side evitará
que o consumo de memória saia pelo teto e acrescentará uma vantagem em ambientes com cluster. Mas,
desde que o estado deva ser enviado de volta e voltar novamente entre o cliente e o servidor, o tempo de
resposta pode aumentar. Você pode configurar o método de preservação de estado, como mostrado no
Exemplo de Código 1-8, no arquivo descritor de deployment da aplicação – WEB-INF/web.xml – através
do parâmetro STATE_SAVING_METHOD para client ou server.

Exemplo de Código 1-8. Alterando o Método de Preservação de Estado no Deployment Descriptor

<context param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context param>

Família de Componentes e Tipo de Componente


A família de componentes é um string que representa o comportamento do componente (um
componente de entrada ou de comando, por exemplo). A família do componente é declarada no arquivo
de configuração do JSF – faces-config.xml – e utilizada para selecionar um Renderer para um componente
em particular. O Exemplo de Código 1-9 mostra como associar um Renderer com uma família de
componentes em particular.

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.

Exemplo de Código 1-10. Mapeamento entre o Ttipo de Componente e a Subclasse de UIComponent

<component>
<component-type>
com.apress.projsf.ProInputDate
</component-type>
<component-class>
com.apress.projsf.ch2.component.pro.ProInputDate
</component-class>

No Exemplo de Código 1-10, uma subclasse de UIComponent – com.apress.projsf.ch2.component.pro.


ProInputDate – foi assinalada como tipo de componente com.projsf.ProInputDate. Por convenção, o tipo
de componente é declarado também na subclasse UIComponent como uma constante –
COMPONENT_TYPE. Isto simplifica a vida dos desenvolvedores, de modo que eles não necessitam
lembrar do tipo de componente para cada componente.

Nota: O prefixo javax.faces é reservado para os tipos de componente definidos na especificação


JSF. Todos os exemplos neste livro utilizam o prefixo com.apress.projsf para os tipos
customizados de componentes.

Converters, Validators, Events e Listeners


Além de fornecer UIComponents, uma implementação JSF também fornece classes auxiliares para
estes UIComponents. Estas classes auxiliares (Nota de tradução: conhecidas como helper classes) são
divididas entre: converters (conversores), validators (validadores) e um modelo de event (evento) e listener
(observadores de eventos). Os converters fornecem conversão de tipo bidirecional entre o valor submetido
de um componente e o correspondente tipo de objeto na camada de modelo. Os validators realizam a
validação no tipo do objeto; por exemplo, eles podem assegurar que uma data não esteja no passado. O
Exemplo de Código 1-11 mostra um componente inputText com um converter de data associado.

Exemplo de Código 1-11. Um Componente inputText com um Converter Date Associado

<h:inputText value=”#{sample.date}” >


<f:convertDateTime pattern=”yyyy-MMM-dd” />
</h:inputText>
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 23

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.

Exemplo de Código 1-12. Um commandButton com um Listener associado

<h:commandButton value=”Login”
action=”success”
actionListener=”#{sample.onLogin}” />

No Exemplo de Código 1-12, um componente commandButton tem duas propriedades – action e


actionListener. Ambas são atributos que aceitam expressões de associação de métodos; a diferença é que
action requer um método que retorne um string e actionListener requer um método que receba um
ActionEvent e retorne void. O valor do string do atributo action é utilizado para propósito de navegação.
Quando o ActionEvent enfileirado é processado, estas expressões de associação de métodos serão
utilizadas para executar os métodos do backing bean referenciados pelo action e pelo actionListener.

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.

Exemplo de Código 1-13. Usando Facets em um componente dataTable

<h:dataTable value=”#{sample.tableList}” var=”rows” >


<f:facet name=”header” >
<h:outputText value=”Contact Information” />
</f:facet>
24 PRO JSF E AJAX

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

Exemplo de Código 1-14. Renderer Ttype Definido no Arquivo de Configuração JSF

<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

Família de Componentes* C o m p o n e n t e Tipo de Componente Renderer Type**


Command UICommand Command
HtmlCommandButton HtmlCommandButton Button
HtmlCommandLink HtmlCommandLink Link
Data UIData Data
HtmlDataTable HtmlDataTable Table
Form UIForm Form
HtmlForm Form Form
Graphic UIGraphic Graphic
HtmlGraphicImage HtmlGraphicImage Image
Input UIInput Input
HtmlInputHidden HtmlInputHidden Hidden
HtmlInputSecret HtmlInputSecret Secret
HtmlInputText HtmlInputText Text
HtmlInputTextArea HtmlInputTextArea Textarea
Continuação
26 PRO JSF E AJAX

Table 1-4. Um Subconjunto de Todas as Famílias de Componentes, seus Componentes e Renderer Types
(continuação)

Família de Componentes* C o m p o n e n t e Tipo de Componente Renderer Type**


Output UIOutput Output
HtmlOutputFormat HtmlOutputFormat Format
HtmlOutputLabel HtmlOutputLabel Label
HtmlOutputLink HtmlOutputLink Link
HtmlOutputText HtmlOutputText Text
Panel UIPanel Panel
HtmlPanelGrid HtmlPanelGrid Grid
HtmlPanelGroup HtmlPanelGroup Group
* O nome completo da família de componente é javax.faces.<nome da tabela>.
** O nome completo do renderer type é javax.faces.< nome da tabela >.

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.

Exemplo de Código 1-15. Um Novo Renderer é Adicionado ao RenderKit Default de HTML

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

Ao não informar o identificador do RenderKit na configuração, o Exemplo de Código 1-15 –


com.apress.projsf.ch2.renderer.html.HtmlInputDateRenderer – é adicionado automaticamente ao RenderKit
HTML default padrão.

Tag Handlers de Ação Personalizada


Já que a linguagem de descrição de página default é JSP, a maioria dos componentes JSF terá uma
custom action JSP. Quando o container JSP encontra uma custom action, ele procura pelo processador
de tag JSF associado com esta ação. O propósito principal do JSF tag handler (processador de tag JSF)
é criar uma instância do componente, utilizando a subclasse específica do renderer, e associar o componente
a um Renderer no primeiro request da página.

Ciclo de Vida de Processamento de Requests


Como um escritor de componentes, é essencial que tenha um entendimento claro sobre o ciclo de vida
do JSF. Uma página construída com componentes JSF passará por um ciclo de vida de processamento
de requests bem definido. Este ciclo tem seis fases – Restore View (Restaurar a view), Apply Request
Values (aplicar os valores do request), Process Validations (processar validações), Update Model Values
(atualizar os valores do modelo), Invoke Application (invocar a aplicação) e Render Response (renderizar
a resposta), como mostrado na Figura 1-8.

Figura 1-8. Ciclo de vida formal do JSF


28 PRO JSF E AJAX

Eis como o processo é dividido:


1. Restore View: Esta fase é responsável por restaurar a hierarquia de componentes do request prévio
e anexá-la ao FacesContext. Se nenhum estado preservado estiver disponível, esta fase é
responsável por criar um novo UIViewRoot, que é o nó raiz na hierarquia de componentes, e
armazená-la no FacesContext.
2. Apply Request Values: Nesta fase, cada componente tem a oportunidade de atualizar seu estado
corrente com informações advindas do request.
3. Process Validations: Esta fase é responsável por processar quaisquer validators ou converters
anexados aos componentes da hierarquia de componentes.
4. Update Model Values: Durante esta fase, todos os objetos de modelos de dados apropriados terão
seus valores atualizados para igualar ao valor local do componente, e os valores locais dos
componentes serão limpos.
5. Invoke Application: Nesta fase, qualquer transmissão de eventos para a aplicação ainda
remanescente será efetuada (ações executadas por HtmlCommandButton, por exemplo).
6. Render Response: Esta fase é responsável por renderizar a resposta para o cliente e armazenar
o novo estado para processamento nos requests subseqüentes.
Para colocar estas seis fases em um contexto de vida real, utilizaremos um exemplo simples onde o
usuário acessará uma aplicação construída com JSF e JSP. Esta aplicação contém uma página simples de
login com alguns campos de entrada para username e password e um botão para validar. Caso o login seja
bem sucedido, o usuário será redirecionado para uma segunda página que exibirá o nome do usuário.

Criando uma Aplicação Utilizando o JSF


Esta aplicação contém três partes essenciais – a descrição da aplicação (JSP), um arquivo de
configuração JSF e um managed bean. Esta aplicação tem duas páginas JSP –login.jspx e result.jspx. O
Exemplo de Código 1-16 mostra a página de login.

Exemplo de Código 1-16. A Página de Login

<?xml version=”1.0" encoding=”utf-8"?>


<jsp:root xmlns:jsp=”http://java.sun.com/JSP/Page” version=”2.0"
xmlns:f=”http://java.sun.com/jsf/core”
xmlns:h=”http://java.sun.com/jsf/html”>
<jsp:output omit-xml-declaration=”true” doctype-root-element=”HTML”
doctype-system=”http://www.w3.org/TR/html4/loose.dtd”
doctype-public=”-//W3C//DTD HTML 4.01 Transitional//EN”/>
<jsp:directive.page contentType=”text/html;charset=utf-8"/>
<f:view>
<html>
<body>
<h:form>
<h:outputText value=”Application Login” />
<h:inputText value=”#{credentials.username}” />
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 29

<h:inputText value=”#{credentials.password}” />


<h:commandButton value=”Login”
action=”success”
actionListener=”#{credentials.onLogin}” />
</h:form>
</body>
</html>
</f:view>
</jsp:root>

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.

Figura 1-9. A P gina de Login

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.

Exemplo de Código 1-17. Regras de Navegação e Managed Beans Para a Aplicação

<?xml version=”1.0" encoding=”utf-8"?>


<jsp:root xmlns:jsp=”http://java.sun.com/JSP/Page” version=”2.0"
xmlns:f=”http://java.sun.com/jsf/core”
xmlns:h=”http://java.sun.com/jsf/html”>
<jsp:output omit-xml-declaration=”true” doctype-root-element=”HTML”
doctype-system=”http://www.w3.org/TR/html4/loose.dtd”
doctype-public=”-//W3C//DTD HTML 4.01 Transitional//EN”/>
<jsp:directive.page contentType=”text/html;charset=utf-8"/>
<f:view>
<html>
30 PRO JSF E AJAX

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

Exemplo de Código 1-18. Regras de Navegação e Managed Beans para a Aplicação

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

Exemplo de Código 1-19. A Lógica da Aplicação

package com.apress.projsf.ch1.application;

import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;

public class CredentialsBean


{
public void onLogin(
ActionEvent event)
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 31

{
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;
}

Inicialização da Aplicação Web


Ao receber um request JSF, a implementação JSF deve iniciar, ou adquirir, referências a vários
processos e serviços que devem estar disponíveis para uma aplicação Web JSF executando em um ambiente
de servlet ou portlet. Para ter acesso a estas referências, a implementação JSF irá invocar várias factories
(objetos que instanciam outros objetos) responsáveis por criar as instâncias necessárias para iniciar a
aplicação JSF.
Quando uma aplicação Web JSF inicia, nossas factories são iniciadas também; cada uma destas
factories é responsável por áreas diferentes dentro de uma aplicação Web JSF:
ApplicationFactory: A classe ApplicationFactory é responsável pela criação da instância da aplicação
(Application), a qual pode ser vista como um serviço que permite, por exemplo, que a instância
de Lifecycle crie e restaure as views JSF (hierarquia de componentes) nos novos requests e
armazene o estado da view JSF.
LifecycleFactory: A LifecycleFactory é responsável por retornar uma instância da classe Lifecycle, que
identifica um lifecycle. A instância default do Lifecycle é responsável por invocar a lógica de
processamento, para implementar a funcionalidade desejada para cada fase do ciclo de vida de
processamento de requests do JSF.
32 PRO JSF E AJAX

RenderKitFactory: A RenderKitFactory é responsável por retornar um RenderKit para a aplicação


Web JSF. Um RenderKit é uma biblioteca de Renderers com uma tecnologia comum de
renderização.
FacesContextFactory: A FacesContextFactory provê um meio de criar uma instância da classe
FacesContext para a implementação JSF, que é utilizada para representar informação
contextual associada ao request e eventualmente à resposta.
A Figura 1-10 mostra os envolvidos na inicialização da aplicação.

Figura 1-10. A criaÁ„o da aplicaÁ„o

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

Fase de Restore View


A primeira fase do ciclo de vida JSF é a Restore View (veja a Figura 1-11) que é responsável por verificar
se esta página foi requisitada anteriormente ou se é um novo request.

Figura 1-11. Fase Restore View durante o request inicial

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

Fase Render Response


Quando o método renderResponse() é invocado durante a fase Restore View, o ciclo de vida pula
diretamente para o método render(), responsável por executar a fase Render Response, como demonstrado
na Figura 1-12.

Figura 1-12. A fase Render Response durante o request inicial

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

Figura 1-13. Informando o ResponseWriter no FacesContext

O Identificador da View JSF: View ID


Dependendo de qual mapeamento é utilizado – prefix (prefixo) ou suffix (sufixo) – o identificador
de view do UIViewRoot é derivado ligeiramente diferente do uniform resource identifier (URI)
do request. Se o mapeamento prefix for utilizado, como em “/faces/*” (que é o mais comum ) para
o FacesServlet, a propriedade viewId é obtida da informação de path vinda após o mapeamento;
por exemplo, “/context-roofaces/login.jspx” irá resultar em um view identifier igual a “/login.jspx”.
Se o mapeamento suffix for utilizado, como “*.jsf”, a propriedade viewId é obtida da informação
de path do servlet do URI do request, após substituir o sufixo com o valor do parâmetro de
inicialização do contexto, cujo nome é dado pela constante: ViewHandler.
DEFAULT_SUFFIX_NAME. Por exemplo, a URI “/context-root/login.jsf” resultará em um
view identifier igual a “/login.jsp” por default, mas é possível alterar o parâmetro de inicialização
de contexto para usar o sufixo “.jspx” como default.

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

Tipo de Conteúdo e Encoding de Caracteres


Quando um servidor envia um documento para um browser no cliente, ele também passa informação
no header Content-type (tipo de conteúdo) do HTTP sobre o tipo MIME (Multipurpose Internet Mail
Extensions) do documento, como “text/html” e o conjunto de caracteres, como UTF-8 ou ISSO-8859-
1. O cliente utiliza esta informação para processar corretamente os bytes oriundos do servidor.
Uma lista de tipos de conteúdos aceitáveis é enviada no header HTTP Accept, do cliente para o
servidor. Isto pode ser utilizado dinamicamente para selecionar o tipo de documento apropriado para
a resposta, ou o desenvolvedor da aplicação pode especificar um conteúdo estático para o documento.
No JSF, o tag <f:view> passa null para a RenderKitFactory como uma lista de tipos de conteúdo
aceitáveis, mesmo que o container JSP esteja ciente da lista completa aceita pelo browser do cliente.
Então, o RenderKit default – RenderKit HTML básico padrão – deve assumir que o tipo de conteúdo
deve ter sido alterado para “text/html”, uma vez que está renderizando apenas HTML. O RenderKit
usa esta informação sobre o tipo de conteúdo e encoding de caracter para criar um ResponseWriter
que possa produzir markup corretamente formatado para o cliente.

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

Figura 1-14. Escrevendo o elemento inicial <form> no buffer de conte­do de <f:view>


CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 37

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

Figura 1-15. A saÌda e o fechamento do elemento </form>


38 PRO JSF E AJAX

O processo continua e todos os componentes aninhados dentro do componente HtmlForm são


renderizados e adicionados ao buffer de conteúdo do <f:view>. Então o tag de fechamento de <h:form>
é executado. O tag <h:form> invoca o método encodeEnd() no Renderer, HtmlFormRenderer, o qual, por
sua vez, chama o método writeState() no ViewHandler. O método writeState() passa um token para o
ResponseWriter, o qual é adicionado ao buffer de conteúdo do <f:view>. O método encodeEnd() então
chama métodos no ResponseWriter para escrever o tag de fechamento para o elemento HTML form - </
form>. A Figura 1-16 mostra o fechamento do tag <f:view>.

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.

Figura 1-16. Substituindo o token pelo estado serializado e fechando </f:view>

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.

Fase Restore View


A primeira parte de um postback é a mesma do request inicial; a fase Restore View executa e chama
o método restoreView() no ViewHandler para restaurar qualquer estado disponível do request prévio. A
Figura 1-17 mostra como restaurar o estado preservado da hierarquia de componentes.

Figura 1-17. Restaurando o estado preservado da hierarquia de componentes


40 PRO JSF E AJAX

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.

Fase Apply Request Values


Na fase Apply Request Values, cada componente de entrada estabelece o valor submetido dos
parâmetros de request, e cada comando de componentes envia um evento para a fila, a ser enviado para
a fase Invoke Application. A Figura 1-18 mostra como a fase Apply Request Values passa novos valores
para os componentes.

Figura 1-18. Aplicando novos valores, passados no request, aos componentes

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.

Fase de Process Validation


Na fase de process validation, a conversão e validação são efetuadas chamando o método
processValidators() no UIViewRoot. A Figura 1-19 mostra a conversão e validação.
CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 41

Figura 1-19. Efetuando a validaÁ„o e convers„o

Este processo irá continuar chamando o método processValidators() recursivamente em cada


componente da hierarquia. Durante a validação de cada componente HtmlInputText, a conversão de tipo
ocorrerá primeiramente no valor submetido de cada componente (um string para outro objeto, por exemplo).
O novo objeto é colocado como um valor local no componente e o valor “submitted” é limpo. O novo objeto
é validado. Se não houver erros, então a próxima etapa é enfileirar um evento ValueChangeEvent que será
disparado ao final da fase.
Se um erro de conversão ou validação ocorrer, uma mensagem correspondente JSF será anexada ao
FacesContext utilizando o componente clientId, e então o método renderResponse() é chamado para indicar que
o ciclo de vida deve pular diretamente para a fase Render Response, após a fase Process Validations completar.

Fase Update Model


Neste ponto do ciclo de vida, todos os valores submetidos foram convertidos e validados, logo, é seguro
colocá-los no modelo de dados. Durante a fase Update Mode, o ciclo de vida JSF passa pela hierarquia
de componentes, chamando o método processUpdates() em cada componente. A Figura 1-20 mostra a fase
Update Model atualizando o modelo.
Para determinar onde armazenar o novo valor, o método processUpdates() utilizará a associação de
valor, a qual é definida o atributo value do componente (por exemplo “#{credentials.username}”). A
associação de valor aponta para uma propriedade em um managed bean (por exemplo, username).
Utilizando associação de valor, o valor local do componente é armazenado no modelo de dados e depois
sendo limpo no componente.
Quaisquer mensagens JSF e erros no modelo – por exemplo, validações implementadas pelo modelo
–, são anexados ao FacesContext com o clientId correspondente. O método renderResponse()
é chamado para indicar que o ciclo de vida deve pular diretamente para a fase Render Response após a fase
Update Model estiver completa.
42 PRO JSF E AJAX

Figura 1-20. Atualizando o modelo de dados

Fase Invoke Application


Na fase Invoke Application é necessário correr a hierarquia de componentes, já que esta fase manipulará
apenas os eventos enfileirados das fases anteriores e, dependendo do resultado, irá continuar até a fase
final – Render Response – ou redirecionar para outra página. A Figura 1-21 mostra a transmissão de eventos
enfileirados para esta fase e o processamento dos métodos associados à ação.

Figura 1-21. Executando a lÛgica de aplicaÁ„o


CAPÍTULO 1 – A FUNDAÇÃO DO JSF: COMPONENTES 43

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.

Postback com Navegação


Quando o ActionListener default está processando um ActionEvent, ele chama uma associação de
método de ação e obtém o resultado, que é um string. Se o resultado retornar null, então o ActionListener
default continuará com o próximo evento na fila. Após todos os eventos terem sido transmitidos, a fase
Invoke Application estará completa e o processamento do ciclo de vida continuará até a fase final – Render
Response. Se o resultado não for null, então o ActionListener default passa o FaceContext, o fromAction
(que é a expressão de associação de método, por exemplo: “credentials.doLogin”) e o outcome (resultado)
para o NavigationHandler. A Figura 1-22 mostra a navegação no caso de postback.

Figura 1-22. NavegaÁ„o com postback


44 PRO JSF E AJAX

As regras de navegação estão definidas no faces-config.xml, que é lido na inicialização, e toda a


informação é armazenada no objeto Application (veja a seção “Modelo de Navegação”). A primeira coisa
que o NavigationHandler faz é verificar se existe uma regra de navegação que seja compatível com a
combinação de fromViewId (obtido do FacesContext), fromAction e outcome.
Podemos lidar com a navegação de duas maneiras. Redirecionar significa um novo request (e, como
bônus, você pode criar um bookmark para a nova página) e inicia o ciclo de vida do JSF novamente; podemos
também fazer com que o método handleNavigation() crie um novo UIViewRoot, coloque-o no FacesContext
e deixe o ActionListener default chamar renderResponse() para iniciar a fase Render Response. Esta
solução replica o comportamento do request inicial na fase Render Response, mas com um novo
identificador de view. A Figura 1-23 mostra a execução do JSP durante o postback.

Figura 1-23. A fase Render Response em um postback

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

A despeito de estarmos mapeando componentes ao invés de criar novas instâncias, o processamento


segue da mesma maneira que no request inicial – renderizando os componentes para o buffer do tag
<f:view>, armazenando o estado, seja no cliente ou na sessão (no servidor), e, finalmente, enviando o
markup do buffer para o container JSP, de modo a ser renderizado (veja a Figura 1-15).

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

<?xml version=’1.0' encoding=’windows-1252'?>


<jsp:root xmlns:jsp=”http://java.sun.com/JSP/Page” version=”2.0"
xmlns:f=”http://java.sun.com/jsf/core”
xmlns:h=”http://java.sun.com/jsf/html”>
<jsp:output omit-xml-declaration=”true” doctype-root-element=”HTML”
doctype-system=”http://www.w3.org/TR/html4/loose.dtd”
doctype-public=”-//W3C//DTD HTML 4.01 Transitional//EN”/>
<jsp:directive.page contentType=”text/html;charset=windows-1252"/>
<f:view>
<html>
<body>
<h:form>
<h:outputText value=”Application Login” />
<h:panelGrid columns=”2">

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

Figura 1-24. RenderizaÁ„o do conte­do diferente de JSF com o rendersChildren true

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.

Figura 1-25. RenderizaÁ„o de conte­do diferente de JSF usando o tag <f:verbatim>

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.

Você também pode gostar