• Nenhum resultado encontrado

API para desenvolvimento de componentes gráficos no JSF

No documento FRAMEWORKS PARA O DESENVOLVIMENTO WEB (páginas 33-44)

O JSF possui uma arquitetura extensível que permite a criação de componentes gráficos para ser feita a interface com o usuário, permitindo assim que terceiros desenvolvam seus próprios componentes gráficos fazendo utilização da API de criação de componentes do JSF.

Segundo Hightower (2007), a funcionalidade dos componentes JSF, tipicamente centraliza-se em duas ações: codificar e descodificar dados. Descodificar é o processo de converter os parâmetros das requisições recebidas para os valores do componente. Codificar é o processo de converter os valores correntes do componente no markup correspondente, ou seja, o HTML.

A criação de um componente no JSF consiste de três tarefas:

Herdar as classes específicas e/ou implementar as interfaces específicas

necessárias. Usualmente se torna necessário a utilização de uma classe ou interface específica para a criação de um componente.

Adicionar as configurações necessárias no arquivo de configuração do JSF.

Assim como muitas outras tarefas no JSF, é necessário ser feita a configuração do componente no arquivo XML (Extensible Markup Language) de configuração do JSF, o faces-config.xml. Para toda extensão desenvolvida no JSF, é necessário possuir uma entrada de configuração correspondente.

Integrar a nova classe (o novo componente) com uma tecnologia de exibição,

como por exemplo a JSP, este sendo portanto o último passo para a utilização do componente no processo de desenvolvimento.

Para o desenvolvimento de um componente, primeiramente deve-se criar sua respectiva classe Java contendo seus atributos e esta herdando uma outra classe do framework JSF de acordo com a tarefa em que o componente será responsável por realizar. Por exemplo, se for desenvolver um componente que irá exibir algum atributo de um backing bean, este componente deve herdar a classe ‘javax.faces.component.UIOutput’ que é responsável pela ligação entre o componente e os atributos que serão recuperados os valores do backing bean.

Caso o componente for renderizar um componente HTML para o cliente (possuir a tarefa de escrever algum código HTML para devolver para o cliente), é necessário este possuir uma classe que será responsável pela criação de todo o código HTML que será devolvido para o cliente, a classe é denominada como o renderer do componente e deve estender a classe ‘javax.faces.render.Renderer’, esta contendo métodos responsáveis pela renderização do código HTML que o componente irá escrever.

E por último, é necessário o componente possuir outra classe que estenda a classe

‘javax.faces.webapp.UIComponentTag’, é através desta classe juntamente com a tag library descriptor (que é um arquivo onde estão todos os atributos utilizados dos componentes e onde

é feito a ligação destes atributos com suas respectivas classes Java) que serão encontrados os atributos que o componente possui e que são utilizados em uma JSP por exemplo.

Exemplificando o que foi mencionado referente à criação de componentes gráficos no JSF, será desenvolvido um componente que renderiza para o cliente um formulário para o preenchimento de login, como a maioria das telas referente a login possui dois campos para a entrada dos dados, ou seja, o login e a senha, será desenvolvido um componente que rederizará estes dois campos para a entrada dos dados, sendo que estes dois campos possuíram relacionamento com atributos de um determinado backing bean de acordo com o que o desenvolvedor mencionar através de uma EL (Expression Language), ou seja, os dados inseridos estarão ligados diretamente com uma classe Java que posteriormente poderá utilizar estes dados informados pelo usuário para fazer a validação do login, se o mesmo é válido ou não.

Classes Java:

O componente possuirá três classes, a classe que representará o componente, uma classe que será o renderer do componente, que conforme já mencionado é responsável por criar os códigos HTML necessários para o componente, e por último possuirá uma classe que conterá as configurações referentes aos atributos que serão utilizados na JSP para a utilização do componente, estes atributos podendo ser denominados por tags.

A classe que representará o componente irá herdar a classe

‘javax.faces.component.UIOutput’, pois esta super classe (classe pai) contém implementações

já prontas no que se refere a escrita de saída em HTML, e como o componente irá escrever códigos, será utilizada a classe UIOutuput, caso o componente fosse um campo que recebe entrada de dados, este deveria herdar a classe UIInput que da mesma forma que a UIOutput é para a saída de dados a UIInput é para a entrada de dados.

1. public class Login extends UIOutput

2. {

3. public static final String FAMILY = "LOGIN_TCC";

4. 5. public Login() 6. { 7. super(); 8. } 9.

10. public String getFamily() 11. {

12. return FAMILY;

13. } 14. }

Exemplo 5.5.1

Conforme o exemplo 5.5.1, outra particularidade da classe é que ela possui o método

getFamily() (linha 10) que retorna a família que este componente pertence, esta família é

utilizada para saber posteriormente qual é o renderer do componente quando for feita a geração do HTML através do arquivo de configuração onde o componente será registrado (esta tarefa será feita posteriormente). Uma das tarefas da classe também é chamar o construtor de sua super classe (UIOutput) este contendo tarefas necessárias para os componentes que geram valores de saída conforme explicado anteriormente (linha 7).

Renderer:

Outra classe Java que o componente conterá é a classe que será o renderer (que conforme já explicado é onde são gerados os códigos HTML que serão enviados para o cliente), para uma classe ser um renderer, esta deve estender a classe

‘javax.faces.render.Renderer’. Portanto o renderer do componente que renderizará o

formulário para login ficará da seguinte forma:

public class LoginRenderer extends Renderer Exemplo 5.5.2

Uma classe renderer pode possuir os seguintes métodos que são (não obrigatoriamente) sobrescritos, pois estes pertencem a super classe Renderer (conforme exemplo 5.5.2) para o controle e geração do código HTML que irá ser devolvido ou enviado para o cliente:

• decode (FacesContext, UIComponent)

o Este método é responsável por recuperar qualquer parâmetro passado pelo

form do HTML e armazenar valores no componente. A primeira tarefa que

este método deve realizar que faz parte de sua especificação é certificar de que os atributos e o contexto não estão nulos.

• encodeBegin (FacesContext, UIComponent)

o É onde é feita a implementação inicial do código HTML que será gerado, é o primeiro método a ser chamado para a renderização do HTML.

• encodeChildren (FacesContext, UIComponent)

o Caso o componente possua outros sub componentes, ou seja, componentes que serão filhos deste, é através deste método que será recuperado os componentes filhos e será feita a lógica necessária para o tratamento de seus sub componentes. Este método só é executado se a classe renderer possuir um outro método, o getRendersChildren() retornando true, este método pertence a super classe Renderer e caso este método não seja sobrescrito, é retornado false, portanto o default é não ser feita a execução do método encodeChildren, este só sendo executado quando a classe que representará o renderer possuir o método getRendersChildren() sobrescrito retornando true.

• encodeEnd (FacesContext, UIComponent)

o Onde é feita a implementação final do código HTML que será gerado, onde pode ser fechada uma tag table que foi iniciada no encodeBegin por exemplo. É o último método a ser invocado no processo de renderização de código HTML do componente que possui o renderer.

Caso o componente não possuir sub componentes, ou seja, não possuir nenhum componente filho, toda a lógica de codificação do HTML pode ser desenvolvida apenas no método encodeBegin.

Concluindo, a codificação do código HTML que o renderer do componente irá gerar possui o seguinte processo: primeiramente é chamado o método encodeBegin, após sua execução é chamado o método encodeChildren, este sendo chamado somente se a classe possuir o método getRendersChildren() retornando true e por último é chamado o método

encodeEnd, finalizando assim o processo de geração do código HTML até onde o

desenvolvedor possui o maior acesso.

1. public boolean getRendersChildren()

2. {

3. return true;

4. }

5. public void encodeBegin(FacesContext context, UIComponent component) throws

IOException 6. {

7. ResponseWriter writer = context.getResponseWriter(); 8. 9. writer.startElement("table", component); 10. writer.startElement("tr", component); 11. writer.startElement("td", component); 12. writer.write((String)component.getAttributes().get("label")); 13. writer.endElement("td");

14. writer.endElement("tr"); 15. writer.flush();

16. } 17.

18. public void encodeChildren(FacesContext context, UIComponent component)

throws IOException 19. {

20. ResponseWriter writer = context.getResponseWriter(); 21. Iterator inputs = component.getChildren().iterator(); 22.

23. UIComponent componente = (UIComponent)inputs.next();

24. writer.startElement("tr", component); 25. writer.startElement("td", component); 26. writer.write("Login: "); 27. writer.endElement("td"); 28. writer.startElement("td", component); 29. componente.encodeBegin(context); 30. componente.encodeEnd(context); 31. writer.endElement("td"); 32. writer.endElement("tr"); 33. writer.startElement("tr", component); 34. writer.startElement("td", component); 35. writer.write("Senha: "); 36. writer.endElement("td"); 37. writer.startElement("td", component); 38. componente = (UIComponent)inputs.next(); 39. componente.encodeBegin(context); 40. componente.encodeEnd(context); 41. writer.endElement("td"); 42. writer.endElement("tr"); 43. writer.flush(); 44. } 45.

46. public void encodeEnd(FacesContext context, UIComponent component) throws

IOException 47. {

48. ResponseWriter writer = context.getResponseWriter(); 49. writer.endElement("table");

50. }

Exemplo 5.5.3

O exemplo 5.5.3 mostra como fica o código que cria todo o conteúdo HTML referente ao componente. Primeiramente na linha 1, o método getRendersChildren esta retornando

true, portanto o método encodeChildren será invocado pelo framework para o tratamento de

seus respectivos filhos ou sub componentes.

No método encodeBegin na linha 5, é recuperado o objeto onde será escrito o código HTML que será devolvido para o browser do cliente, este sendo o objeto writer do tipo

ResponseWriter na linha 7, contendo o retorno do método context.getResponseWriter() que

retorna o objeto de escrita (do tipo ResponseWriter) da requisição corrente para posteriormente ser devolvida com novos códigos HTML.

Para ser inserida uma tag HTML no response que será enviado para o cliente, é utilizado o método startElement presente na classe ResponseWriter, através deste método é que se inicia uma tag, por exemplo, para iniciar a tag <table>, utilizaria-se o método

startElement da seguinte forma: <objeto>.startElement(“table”), e o framework renderizaria

a tag table da forma correta no cliente e para fechar uma tag HTML, utiliza-se o método

endElement, portanto o fechamento da mesma tag table, seria feito da seguinte forma: <objeto>.endElement(“table”) que resultaria no código HTML </table>.

Os atributos inseridos na JSP pelo desenvolvedor são recuperados desta forma:

componente.getAttributes().get("nome_do_atributo"), portanto conforme a linha 12, será

inserido no código HTML criado pelo componente o que o desenvolvedor especificou no atributo label na JSP que pode ser melhor observado na utilização deste componente na JSP, mais a frente.

Após ser executado o encodeBegin, será executado o método encodeChildren para o tratamento dos filhos. Da mesma forma que no encodeBegin é recuperado o objeto que representará a resposta (ou o response) que será enviada para o cliente, é feita esta recuperação no encodeChildren, conforme linha 20. Os filhos do componente são recuperados na linha 21, estes sendo tratados através de um objeto do tipo Iterator, onde se pode, por exemplo, ser feito um laço/loop para o tratamento de todos os filhos, percorrendo estes componentes filhos, caso a quantidade de componentes filhos que um componente possuir for grande ou indeterminada. Como no caso deste componente irão existir apenas dois componentes filhos, um campo para entrada do login e um campo para a entrada da

senha, portanto não foi feito um laço para a recuperação dos filhos. O primeiro componente

filho recuperado é armazenado no objeto ‘componente’ (linha 23) do tipo UIComponent que representa os componentes gráficos de interface com o usuário do JSF e nas linhas 29 e 30 são chamados os métodos encodeBegin e encodeEnd respectivamente do componente filho, este componente filho será do tipo UIInput que é um componente já definido e implementado no JSF para a inserção de dados, portanto será feita a renderização do código HTML necessário dos componentes filhos através dos métodos encodeBegin e encodeEnd dentro da tag HTML <td> representando um dado de uma linha de uma tabela HTML, esta

tag sendo iniciada na linha 28 e fechada na linha 31, criando-se portanto:

<td>

código do HTML renderizado pelos métodos encodeBegin e encodeChildren

</td>

O mesmo procedimento é feito para o segundo componente que é um novo campo para a inserção de dados, na linha 38 é recuperado o próximo componente filho através do iterator e nas linhas 39 e 40 são invocados os métodos encodeBegin e encodeChildren para a renderização do código HTML deste segundo componente filho. Como o componente renderizará uma tabela HTML para a geração deste formulário para o login, o segundo componente é inserido em uma nova linha da uma tabela HTML, cuja tag é representada por

<tr>, esta é iniciada na linha 33 e fechada na linha 42, este mesmo procedimento de iniciar

uma nova linha para a inserção do componente filho foi feito para o primeiro componente filho, onde a tag <tr> foi iniciada na linha 24 e fechada na linha 32.

E finalizando o processo de renderização do código HTML que o componente gera para ser feito o envio para o browser do cliente, o framework faz a chamada do método

encodeEnd (linha 46), onde este nada mais faz do que fechar a tag <table> (linha 49) que foi

iniciada no encodeBegin (linha 9).

Até o momento o componente possui a sua classe representativa e o seu Renderer, por último é necessário possuir também uma classe contendo o devido tratamento para as tags ou os atributos que o desenvolvedor irá utilizar na JSP para a renderização do componente no

browser do usuário.

As classes que fazem este tratamento dos atributos devem estender a classe

javax.faces.webapp.UIComponentTag, esta possuindo o devido tratamento e as devidas

tarefas para o componente. Portanto conforme o exemplo 5.5.4, a classe possuirá a seguinte assinatura:

public class LoginTag extends UIComponentTag Exemplo 5.5.4

Esta classe deve implementar alguns métodos contidos na classe UIComponentTag, estes sendo responsáveis por retornar informações do componente para que o framework recupere as devidas classes no arquivo de configuração faces-config.xml. Os métodos que devem ser implementados são: getComponentType, getRendererType e setProperties, conforme segue no exemplo 5.5.5.

1. private static final String LOGIN = "LOGIN";

2. private static final String LOGIN_RENDERER = "LOGIN_RENDERER"; 3.

4. public String getComponentType()

5. {

6. return LOGIN; 7. }

8.

9. public String getRendererType()

10. {

11. return LOGIN_RENDERER; 12. }

13.

14. protected void setProperties (UIComponent component)

15. {

16. super.setProperties(component);

17. component.getAttributes().put("label", label); 18. }

Exemplo 5.5.5

No exemplo 5.5.5 na linha 4, o método getComponentType retorna o tipo do componente, para que o framework localize a respectiva classe do componente no arquivo de configuração (faces-config.xml). O método getRendererType retorna o tipo do Renderer do componente para ser possível ser feita a localização da classe que representa o Renderer do componente. E por último o método setProperties é responsável por armazenar no contexto da aplicação os atributos que o desenvolvedor utilizou do componente na JSP para que posteriormente seja possível recuperar estes atributos, assim como foi feito na linha 12 do exemplo 5.5.3. Portanto o atributo label é recuperado da JSP e armazenado no componente na linha 17 do exemplo 5.5.5 e é recuperado para inserir no código HTML, no renderer do componente, no exemplo 5.5.3.

Para uma melhor manutenção do código e facilidade no desenvolvimento, é uma boa prática os atributos retornados pelos métodos getComponentType e getRendererType, serem constantes, assim como foram declarados nas linhas 1 e 2 do exemplo 5.5.5. Portanto o tipo do componente é “LOGIN” e o tipo do renderer do componente é “LOGIN_RENDERER”, estes valores são utilizados pelo framework para encontrar quais as classes Java serão utilizadas em todo processo que o componente realiza.

Configuração do componente:

Conforme já explicado, todo componente de interface do JSF deve ser configurado para que o framework possa recuperar suas classes e recursos corretamente. A configuração dos componentes são feitas no arquivo faces-config.xml que já foi utilizado para outros fins, é neste arquivo que ficam as principais configurações do JSF.

Segue no exemplo 5.5.6 a configuração necessária para o funcionamento do componente no arquivo de configuração, juntamente com sua explicação:

1. <component>

2. <component-type>LOGIN</component-type>

3. <component-class>exemplotcc.Login</component-class> 4. </component>

Exemplo 5.5.6

A primeira etapa que deve ser feita é especificar a classe que representará o componente, esta sendo a classe mostrada no exemplo 5.5.1. Esta especificação é inserida dentro da tag <component>, onde <component-type> conterá o tipo do componente, este sendo retornado pelo método getComponentType na linha 6 do exemplo 5.5.5. O framework recuperando qual o tipo do componente, através da classe que trata os atributos do componente, irá verificar no arquivo de configuração, na tag <component-class> qual a classe do componente para ser feito a execução do componente que conforme a linha 3 do exemplo 5.5.6 a classe que representa o componente é a classe Login que esta localizada na

package exemplotcc.

O próximo passo a ser realizado é configurar no mesmo arquivo o renderer do componente, ou seja, qual será a classe que representará o renderer.

1. <render-kit> 2. <renderer>

3. <description>Renderer para o componente de login</description> 4. <component-family>LOGIN_TCC</component-family> 5. <renderer-type>LOGIN_RENDERER</renderer-type> 6. <renderer-class>exemplotcc.LoginRenderer</renderer-class> 7. </renderer> 8. </render-kit> Exemplo 5.5.7

Conforme o exemplo 5.5.7, a configuração do renderer deve ser feita na tag <render-

kit>, esta contendo a sub tag <renderer> (linha 2) que a partir desta sub tag será

efetivamente configurado o renderer. Na linha 3, encontra-se a descrição do rederer, esta visando facilitar a manutenção da aplicação e até mesmo o desenvolvimento, facilitando por exemplo a visualização das tarefas de um determinado renderer, uma vez que estas tarefas estando descritas na tag <description>, o desenvolvedor somente lendo sua especificação já sabe o os principais fundamentos do renderer. Na linha 4, a tag <component-family> deve conter o conteúdo retornado pelo método getFamily que conforme a linha 12 do exemplo 5.5.1, retorna “LOGIN_TCC”, portanto o framework consegue localizar seu renderer através da família do componente retornada pela sua respectiva classe. Na linha 5, na tag <renderer-

type>, se encontra qual o tipo do renderer, este sendo retornado pelo método getRendererType na classe responsável por tratar os atributos do componente (conforme

linha 11 do exemplo 5.5.5). E por último na linha 6 do exemplo 5.5.7 é especificado qual a classe Java que será o renderer do componente, na tag <renderer-class>, neste componente criado como exemplo, o renderer será a classe LoginRenderer que se encontra no pacote

exemplotcc.

Utilização do componente em uma tecnologia de visualização:

Conforme já mencionado anteriormente, a última etapa para a completa utilização de um componente de interface gráfica com o usuário no JSF, é integrar este novo componente

com uma tecnologia de exibição, no exemplo que segue da utilização do componente, será utilizada a tecnologia JSP.

A tecnologia JSP possui a possibilidade de se desenvolver módulos reutilizáveis, estes chamados de ações customizáveis (também conhecido por custom actions), uma ação customizável é invocada quando é feita a utilização de uma tag customizável dentro de uma página JSP. Essas tags devem ser definidas em um arquivo denominado por tag library (que no português significa biblioteca de tags). As particularidades de um tag library são: deve ser um arquivo com a extensão TLD (Tag Library Descriptor) e deve possuir determinadas regras em seu conteúdo, essas regras são padronizadas para a utilização em qualquer tag

library. No exemplo 5.5.8 segue as configurações necessárias somente referente à utilização

do componente criado para a exibição de um formulário de login. 1. <uri>tcc_components</uri>

2. <description>TCC componentes tags</description> 3. 4. <tag> 5. <name>login</name> 6. <tag-class>exemplotcc.LoginTag</tag-class> 7. <attribute> 8. <name>label</name> 9. </attribute> 10. </tag> Exemplo 5.5.8

Conforme no exemplo 5.5.8, na primeira linha é inserida a identificação da tag library, no atributo <uri> (que significa URI - Uniform Resource Identifier, que traduzindo seria Identificador de Fonte Uniforme) para ser utilizada na JSP posteriormente. Na segunda linha é inserida uma descrição referente a tag library.

Uma tag é criada na tag library através do atributo <tag> (linha 4 do exemplo 5.5.8), no atributo <name> é informado o nome da tag criada que será utilizada na JSP (linha 5), no atributo <tag-class> é informado a classe que será correspondente desta tag criada, que conforme a linha 6 é a classe LoginTag presente no pacote exemplotcc (esta classe sendo a mesma mostrada no exemplo 5.5.5). E finalmente são informados quais os atributos que serão utilizados na tag criada, os atributos são criados na tag library através da utilização do atributo <attribute> que dentro deste atributo esta contido o atributo <name>, este sim contendo o nome do atributo que será utilizado na tag na JSP (conforme linhas 7, 8 e 9).

Tendo a tag library configurada para as tags e atributos que o componente utilizará, resta somente utilizar o componente na JSP para esta comandar a geração do código HTML no browser do cliente posteriormente.

Primeiramente, é necessário inserir na JSP a identificação da tag library que conterá as

tags e atributos que o componente utilizará, esta inserção é feita conforme mostra o exemplo

5.5.9.

<%@ taglib uri="tcc_components" prefix="tcccomponent" %> Exemplo 5.5.9

No exemplo 5.5.9, o atributo uri indica qual a tag library será utilizada, e conforme foi mostrado no exemplo 5.5.9 na linha 1, a identificação da tag library que contém as

No documento FRAMEWORKS PARA O DESENVOLVIMENTO WEB (páginas 33-44)

Documentos relacionados