JSF par la pratique : Erreur à eviter
Date de publication : 04 April 2010
		Par
		Faissal Boutaounte   (http://faissal-boutaounte.developpez.com/) (Blog)
 
		
		Cet article a pour but de clarifier des points  qui entrainent souvent les débutants JSF à commettre des erreurs  en utilisant les différents types d'actions disponibles avec JSF.
		
	 
		I. Des actions qui ne s'exécutent pas
			
			
			
			
			
			I-A. Mauvaise utilisation de l'attribut rendered
				
				
				
				
				
				
				
				
				
				
				
			
		
		II. Mauvaise utilisation de l'attribut rendered
			
		
		III. Conclusion
			
			
			 
		
	
		I. Des actions qui ne s'exécutent pas
			
			
				Les actions sont un concept très fort dans JSF il permet d'associer un bouton ou un lien dans une page 
				html a une action (une méthode) dans une classe JAVA (un managed bean). Ceci dit qu'il ya derrière 
				un système très fort qui permet de gérer tous cela, l'ignorance de ce système (architecture de JSF) 
				entrainera dans plusieurs cas des erreurs dans l'utilisation de ces outils. Partons d'un exemple 
				très simple un bouton qui exécute une action, tous ce dont on a besoin pour ça c'est : 
			
			
				 
			
| 
				packageedu.faissal.jsf;publicclassSimpleBean{privateString nom;publicStringgetNom(){returnnom;}publicvoidsetNom(String nom){this.nom=nom;}publicStringaction(){this.nom=returnnull;}}
 | 
| 
			<%@ page language="java" pageEncoding="ISO-8859-1"%><%@ taglib uri="http://java.sun.com/jsf/html" 								prefix="h"%><%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%><!DOCTYPE HTML 								PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head></head><body><f:view>Hello,<br><h:form><h:outputText value="#{nomDusimpleBean.nom}"></h:outputText><br/><h:commandLink value="cliquez sur!" action="#{nomDusimpleBean.action}"></h:commandLink></h:form></f:view></body></html>
 | 
| 
			<managed-bean><managed-bean-name>nomDusimpleBean</managed-bean-name><managed-bean-class>edu.faissal.jsf.SimpleBean</managed-bean-class><managed-bean-scope>request</managed-bean-scope></managed-bean>
 | 
I-A. Mauvaise utilisation de l'attribut rendered
				
				
					Si on modifie le lien qui déclenche notre action, en ajoutant une condition pour l'attribut rendrer , 
					qui l'affichera seulement si un paramètre nomer test est passer dans la requête notre code sera 
					donc comme ça : 
				
| 
				<h:commandLink rendered="#{param['test'] == 'montrer'}"									value="Vous pouvez clicker sur moi pour voir le changement !"				action="#{nomDusimpleBean.action}"></h:commandLink>
 | 
					En suite on appel la page en ajoutant un paramètre test=monter dans la requête, on clique sur le lien 
					et rien ne se passe ! Oui l'action ne s'est pas exécutée ! Le diagnostique a faire lorsque une action 
					ne s'exécute pas est de voir tout d'abord s'il n'y a pas des erreurs de validation et puisque notre 
					exemple ne contient pas des règles de validation alors c'est pas ça notre problème. 
				
				
					Pour comprendre le problème il faut alors commencer par le cycle de vie JSF. Après le clique le navigateur 
					enverra une requête http est envoyé au serveur et justement c'est la servlet FacesServlet qui s'occupe 
					de répondre a cette requête. FacesServlet est ensuite responsable d'enchainer les six phase du cycle 
					de vie de JSF : 
				
				
					- 
						Restore View 
					
- 
						Apply Request Values 
					
- 
						Process Validations
					
- 
						Update Models Values
					
- 
						Invoke Application
					
- 
						Render Response
					
					Pour lancer une action JSF commence en premier lieu et suite à la restauration de la vue par vérifier si le bouton a été source de la soumission du formulaire. Pour faire ce la on parcourt l'arbre des composantes en appelant la méthode UIComponent.processDecodes(javax.faces.context.FacesContext context) :
				
				| 
				publicvoidprocessDecodes(FacesContext context){if(context==null)thrownewNullPointerException("context");if(!isRendered())return;for(Iterator<UIComponent>it=getFacetsAndChildren(); it.hasNext();){it.next().processDecodes(context);}try{decode(context);}catch(RuntimeException e){context.renderResponse();throwe;}}
 | 
					Cette méthode vérifie la propriété rendered (la ligne 2 ) si elle est égale à false elle ne continue pas sinon elle appelle processDecode des composantes filles ensuite  decode(FacesContext facesContext, UIComponent uiComponent) qui elle appel  la méthode queueEvent(javax.faces.event.FacesEvent event); pour mettre l'événement dans la queue afin qu'il puisse être exécuté plus tard dans la phase 5.
				
				
					Normalement notre action sera exécutée lors de la 5ieme phase, mais après le click sur le lien, remarquez que la requête ne contient plus notre paramètre test, ce qui fait que notre lien va avoir l'attribut rendered égale à false  donc il notre bouton ne va pas mettre l'événement qui lui est associé dans la queue des événement ce qui fait qu'il notre méthode ne sera pas exécutée.
				
				
				
			
		
		II. Mauvaise utilisation de l'attribut rendered
			
		
		III. Conclusion
			
			
				La même erreur pourra se reproduire au cas ou vous utilisez un dataTable dont la liste est remplie selon un paramètre de la requête et dans ce cas une fois vous cliquez sur le lien JSF essayera de remplir la table à nouveau et y mettre les boutons mais puisque le paramètre n'existe plus dans la nouvelle requête alors la liste ne sera pas remplie et le bouton cliqué n'existera pas et ne pourra pas lancer l'action qui lui est associée.
Il faudrai essayer au maximum de comprendre le " comment ça marche " de la plus part des chose qu'on utilise dans notre programmation  pour eviter des erreurs simple mais  qui peuvent être difficiles a résoudre.
			
			 
		
	

