Como Depurar o Ciclo de Vida do JSF (Java Server Faces)

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (1)  (0)

Veja neste artigo como depurar as 6 fases do ciclo de vida do JSF (Java Server Faces) para entender como o JSF se comporta por trás dos panos.

Ciclo de vida JSF

O JSF (Java Server Faces) é um poderoso framework para desenvolvimento de aplicações Web em Java, veio com o intuito de substituir a “velha” interface em JSP por uma mais moderna e de fácil utilização, assim o desenvolvedor não precisa se preocupar com códigos HTML, layout, entre outros aspectos que fogem do real objetivo da aplicação.

Para se utilizar o JSF é necessário o entendimento do seu ciclo de vida, assim o desenvolvedor poderá ter noção do que acontece de forma transparente porém muito importante.

O JSF possui 6 ciclos, são eles:

  • Restore View
  • Apply Request View
  • Process Validations
  • Update Model Values
  • Invoke Application
  • Render Response

Explicaremos cada fase através de exemplos práticos do JSF, mas antes precisaremos configurar o Listener que será responsável por monitorar essa mudança de estados do JSF, para isso implementaremos uma interface chamada PhaseListener. Veja na listagem 1 como ficará nossa interface.

Listagem 1: Implementando a Interface PhaseListener

	package br.com.debugjsf.listener;

	import javax.faces.event.PhaseEvent;
	import javax.faces.event.PhaseId;
	import javax.faces.event.PhaseListener;

	public class LifeCycleListener implements PhaseListener {

	    public PhaseId getPhaseId() {
	        return PhaseId.ANY_PHASE;
	    }

	    public void beforePhase(PhaseEvent event) {
	        System.out.println("INICIANDO FASE: " + event.getPhaseId());
	    }

	    public void afterPhase(PhaseEvent event) {
	        System.out.println("FINALIZANDO FASE: " + event.getPhaseId());
	    }

	}

Vamos a explicação do código acima: Criamos uma classe que implementa o PhaseListener, nesta temos os seguintes métodos:

  • getPhaseId(): Apenas retorna um PhaseId que pode ser um daqueles 6 que citamos logo no inicio (1 - Restore View, 2 - Apply Request View, 3 - Process Validations, 4 - Update Model Values, 5 - Invoke Application e 6 - Render Response).
  • beforePhase(): Antes de uma determinada fase iniciar este método é chamado.
  • afterPhase(): Depois de uma determinada fase terminar este método é chamado.

Após termos nosso PhaseListener implementado, vamos configurar o nosso arquivo faces-config.xml para dizer a nossa aplicação quem será o nosso Listener, ou seja, apontar qual será a classe responsável por escutar as mudanças de fase do JSF. Veja na listagem 2 como ficou a configuração do nosso faces-config.xml.

Listagem 2: Configurando faces-config.xml

<lifecycle>
    <phase-listener>br.com.debugjsf.listener.LifeCycleListener</phase-listener>
</lifecycle>

Temos enfim nossa aplicação configurada para escutar todas as fases do JSF, partiremos agora para os exemplos em cada fase. A saída de ciclo completo do JSF no console deve ser algo parecido com a listagem 3.

Listagem 3: Saída no console de um ciclo completo JSF

INICIANDO FASE: RESTORE_VIEW 1
	FINALIZANDO FASE: RESTORE_VIEW 1
	INICIANDO FASE: APPLY_REQUEST_VALUES 2
	FINALIZANDO FASE: APPLY_REQUEST_VALUES 2
	INICIANDO FASE: PROCESS_VALIDATIONS 3
	FINALIZANDO FASE: PROCESS_VALIDATIONS 3
	INICIANDO FASE: UPDATE_MODEL_VALUES 4
	FINALIZANDO FASE: UPDATE_MODEL_VALUES 4
	INICIANDO FASE: INVOKE_APPLICATION 5
	FINALIZANDO FASE: INVOKE_APPLICATION 5
	INICIANDO FASE: RENDER_RESPONSE 6
	FINALIZANDO FASE: RENDER_RESPONSE 6

Configurando a aplicação de exemplo no JSF

Vamos primeiramente configurar nossa página XHTML, que usaremos para realizar a depuração.

Listagem 4: teste.xhtml


	<h:form>
    <h:inputText
        binding="#{myBean.inputComponent}"
        value="#{myBean.inputValue}"
        valueChangeListener="#{myBean.inputChanged}">
        <f:converter converterId="myConverter" />
        <f:validator validatorId="myValidator" />
    </h:inputText>
    <h:commandButton
        value="submit"
        action="#{myBean.action}" />
    <h:outputText
        binding="#{myBean.outputComponent}"
        value="#{myBean.outputValue}" />
    <h:messages />
</h:form>

Vamos as explicações:

  • input text: Este componente está realizando um binding com a propriedade inputComponent do nosso ManagedBean, seu valor é armazenado na propriedade inputValue do ManagedBean, temos ainda um listener associado a ele (inputChanged) que escuta toda vez que alguma alteração é realizada no valor deste campo. Para finalizar este componente, temos ainda um conversor e um validador associados ao mesmo.
  • commandButton: O nosso commandButton dispensa explicações, ele apenas aciona um action em nosso ManagedBean.
  • outputText: Por fim, este componente que é apenas um “label” possui um binding também em nosso ManagedBean e um atributo associado ao seu valor.

Vamos agora ver como será nosso ManagedBean.

Listagem 5: MyBean.java

package br.com.debugjsf.mb;

	import javax.faces.component.html.HtmlInputText;
	import javax.faces.component.html.HtmlOutputText;
	import javax.faces.event.ValueChangeEvent;

	public class MyBean {

	    //Componentes para Binding
	    private HtmlInputText inputComponent;
	    private HtmlOutputText outputComponent;

	    //Armazena valores dos componentes
	    private String inputValue;
	    private String outputValue;

	    public MyBean() {
	        log("constructed");
	    }

	    public void action() {
	        outputValue = inputValue;
	        log("succes");
	    }

	    public HtmlInputText getInputComponent() {
	        log(inputComponent);
	        return inputComponent;
	    }

	    public String getInputValue() {
	        log(inputValue);
	        return inputValue;
	    }

	    public HtmlOutputText getOutputComponent() {
	        log(outputComponent);
	        return outputComponent;
	    }

	    public String getOutputValue() {
	        log(outputValue);
	        return outputValue;
	    }

	    public void setInputComponent(HtmlInputText inputComponent) {
	        log(inputComponent);
	        this.inputComponent = inputComponent;
	    }

	    public void setInputValue(String inputValue) {
	        log(inputValue);
	        this.inputValue = inputValue;
	    }

	    public void setOutputComponent(HtmlOutputText outputComponent) {
	        log(outputComponent);
	        this.outputComponent = outputComponent;
	    }
          
          //Escuta por alterações do inputText e escreve no console quando houver
	    public void inputChanged(ValueChangeEvent event) {
	        log(event.getOldValue() + " to " + event.getNewValue());
	    }

	    //Escreve um LOG no console, para acompanharmos o ciclo de vida    
	    private void log(Object object) {
	        String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
	        System.out.println("MyBean " + methodName + ": " + object);
	    }
	}

E no nosso faces-config.xml configuraremos o ManagedBean assim como na listagem abaixo.

Listagem 6: Configurando faces-config.xml para o ManagedBean

<converter>
    <converter-id>myConverter</converter-id>
    <converter-class>br.com.debugjsf.util.MyConverter</converter-class>
</converter>
<validator>
    <validator-id>myValidator</validator-id>
    <validator-class>br.com.debugjsf.util.MyValidator</validator-class>
</validator>
<managed-bean>
    <managed-bean-name>myBean</managed-bean-name>
    <managed-bean-class>br.com.debugjsf.mb.MyBean</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

Vamos recapitular o que temos até agora:

  • Configuramos o nosso PhaseListener para escutar as alterações de fase do JSF
  • Criamos uma aplicação exemplo para testar nosso PhaseListener, onde essa aplicação é composta por: 1 view (teste.xhtml), 1 ManagedBean (MyBean.java), 1 Converter e 1 Validator. Então vamos agorar criar nosso Converter e nosso Validator.

Listagem 7: Criando o Converter da nossa aplicação

package br.com.debugjsf.util;

	import javax.faces.component.UIComponent;
	import javax.faces.context.FacesContext;
	import javax.faces.convert.Converter;

	public class MyConverter implements Converter {

	    public Object getAsObject(FacesContext context, UIComponent component, String value) {
	        System.out.println("MyConverter getAsObject: " + value);
	        return value;
	    }

	    public String getAsString(FacesContext context, UIComponent component, Object value) {
	        System.out.println("MyConverter getAsString: " + value);
	        return (String) value;
	    }

	}

Listagem 8: Criando o Validator da nossa aplicação

package br.com.debugjsf.util;

	import javax.faces.component.UIComponent;
	import javax.faces.context.FacesContext;
	import javax.faces.validator.Validator;
	import javax.faces.validator.ValidatorException;

	public class MyValidator implements Validator {

	    public void validate(FacesContext context, UIComponent component, Object value)
	        throws ValidatorException
	    {
	        System.out.println("MyValidator validate: " + value);
	    }

	}

Enfim temos nossa aplicação totalmente criada e configurada para escutar as fases do JSF, é óbvio que você pode adaptar o PhaseListener para sua aplicação, colocamos esta apenas para exemplificar o uso deste.

Conclusão

Enfim, o objetivo deste artigo não é explicar com detalhes o ciclo de vida do JSF, e sim configurar um depurador para acompanhar na prática o ciclo de vida deste framework, pois melhor que a teoria, é a prática. Tendo o conhecimento básico de cada ciclo de vida e acompanhando este depurador, você conseguirá ter uma visão melhor de como funciona tal mecanismo e verá a teoria se aplicando na prática.

Isso porque muitos desenvolvedores sentem dificuldade de “ver” como funciona o ciclo de vida do JSF, pois este é totalmente transparente ao desenvolvedor.

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?