le tag debug de Facelets

Facelets possède un tag très utile : le tag ‘debug’

Il permet d’obtenir l’arbre des composants JSF de la page affichée ainsi que les variables ’scopées’.

Pour cela il suffit de mettre un tag du style:

<ui:debug hotkey=”x” rendered=”true”/>

où ‘x’ et la touche sur laquelle on souhaite appuyé pour affichée la pop-up de debug.

En effet, si l’on met le code suivant:

<ui:debug hotkey=”p” rendered=”true”/>

après la balise body par exemple, il suffira de faire Crtl + Shift + P pour afficher une fenêtre pop-up comme celle-ci:

debug pop-up

on peut alors visualiser l’arbre des composant en html:

composant tree debug

et les variables ’scopées’:

scoped variables debug

Cela peut s’avérer pratique, quand on a des soucis d’affichage par exemple.

voici une autre page explicative en anglais :Facelets Debug Tag

Eclipse TPTP

Le plugin TPTP (Test & Performance Tools Platform Project) d’Eclipse permet de faire du monitoring, de tester et de mesurer les performances de ses applications. Voici un article explicatif : article

Installation :

Le plugin est installé d’office dans Eclipse Europa. Sinon voici l’url de son update Site : http://eclipse.org/tptp/updates/site.xml

Utilisation :

Pour profiler son application, on clique sur le bouton suivant :tptp1

A partir duquel on peut faire ‘open run dialog’

tptp2

Mettons que l’on veuille tester un programme java :

tptp3

On indique la classe ‘main’ à exécuter puis les éléments à ‘profiler’ dans l’onglet monitor :

tptp4

Puis on lance l’analyse en cliquant sur ‘Profile’

La perspective ‘Profiling and Logging perspective’ s’ouvre. Une fois l’execution terminée, on peut faire un clic-droit sur le type du profile effectué (Execution Time Analysis par exemple) pour demander l’affichage du résultat sous différentes formes : graphique, statistiques, diagramme de séquence, etc.

tptp5

pour obtenir par exemple un diagramme de séquence ou les statistiques

RedHat Developer Studio

Red Hat a annonçait d’ici la fin 2007 la commercialisation de Red Hat Developer Studio, un environnement de développement Open Source intégrant des outils basés sur Eclipse et les solutions JBoss et Red Hat Enterprise. Il est le résultat du partenariat de Red Hat et d’Exadel annoncé en mars 2007.

Si la version finale ne sortira qu’a la fin de l’année, les versions ‘nightly builds’ sont d’ors et déjà accessibles ici:

http://download.jboss.org/jbosstools/builds/nightly/

 

Installation :

-Télécharger une des versions : ‘JBossTools-version-nightly-ALL-win32.zip’ depuis le lien ci-dessus. Attention à télécharger la version la plus récente contenant TOUS les plugins. A l’heure actuelle il s’agit de la version 200707210217 disponible ici :

http://download.jboss.org/jbosstools/builds/nightly/200707210217-nightly/

-Dézipper l’archive et copier, comme d’habitude, les fichiers dans les répertoires features et plugins d’eclipse.

-Démarrer votre Eclipse. Vous devriez avoir une suite d’écran vous remerciant d’utiliser RedHatDevelopperStudio et vous invitant à configurer votre server Jboss. Cette dernière étape peut évidemment être sautée si vous n’avez aucun serveur de ce type à configurer dans Eclipse.

 

Voila, RedHatDevelopperStudio est installé. Nous allons maintenant voir comment utiliser le ‘Red Hat HTML Editor’ pour développer nos facelets (ou jsp) avec une interface visuelle.

 

-Il suffit pour cela d’ouvrir un fichier .xhtml avec le ‘Red Hat HTML Editor’. Maintenant que le plugin est installé cela doit se faire automatiquement. Vous obtenez votre éditeur. Pour pouvoir travailler avec les templates (tout l’interet des facelets) et les images dans la visualisation, il faut que les chemins soient relatifs ou absolus. On ne peut pas avoir de visualisation avec des liens du type :

${facesContext.externalContext.request.contextPath}/

media/images/home.gif

Il faut par exemple des chemins du type :

../../media/images/home.gif ou ./media/images/home.gif

Vous pouvez, pour cela configurer les chemins en cliquant sur le bouton suivant (à gauche de la visualisation) :

redhatbouton

 

Et en configurant ‘Actuel Run-time Absolute Folder’ et ‘Actuel Run-time Relative Folder’

Voici un exemple :

<img

src=“./media/images/CMonDossierWeb/info.gif” (relatif)

border=“0″ />

<img

src=“../../media/images/CMonDossierWeb/home.gif” (absolue)

border=“0″ />

<img

src=“${facesContext.externalContext.request.contextPath}/media/images/CMonDossierWeb/modify.gif”

border=“0″ />

 

Donne :

redhatView

 

Avec les chemins suivants :

redhatpath

Pour finir sur un exemple, cette visualisation est le résultat de 3 templates imbriqués:

visualisation templates

Remarque : A noter que j’ai testé ce plugin sous la version Europa d’Eclipse.

 

Compatibilité IE – Firefox

Ayant jusqu’ici travaillé quasi exclusivement sur Firefox, j’ai tenté la compatibilité sous IE. J’ai donc bien sur rencontré plusieurs problèmes:

Problèmes :

1- j’ai un formulaire avec un champ inputText. Quand je fais ‘Enter’ sur ce champ sous Firefox cela lance direct l’action de mon bouton au type ’submit’ MAIS sous IE : rien, j’ai l’impression qu’il recharge la page.

<h:inputText id="annee" value ="#{rechercheController.annee}" size='4' 
maxlength='4' onkeyup="javascript:verifAnnee();"/>
<FONT COLOR="RED"><h:outputText id="anneeAlert" value=""/></FONT>
...
<h:commandButton id="validButton" action="#{rechercheController.chercher}"
 type="submit" value="Rechercher" />

...

<script language='javascript'>
function verifAnnee() {
        if(document.getElementById("formRecherche:annee").value=='') {
        document.getElementById("formRecherche:anneeAlert").innerHTML=
                            "Veuillez entrer une année";
        }else{
        document.getElementById("formRecherche:anneeAlert").innerHTML='';
        }
}

</script>

 

2-Je fais du transfert de fichiers pdf générés à la volée. Je passe par une servlet qui met l’objet (Document itext) en session. Sous Firefox, tout se passe bien, il me demande si je veux l’enregistrer ou l’ouvrir: parfait. Sous IE soit (suivant la page de création du pdf : j’ai deux pages qui propose une création de pdf) il me dit ‘le fichier ne peut être ouvert voulez vous l’enregistrer’ soit il l’ouvre direct sous Acrobat reader qui plante.

 

3-Sur une de mes pages qui génère un pdf, au moment du clic sur le lien j’affiche un gif (permettant à l’utilisateur de comprendre qu’il se passe quelque chose), puis je lance l’action de création du fichier. Sous Firefox, bien sur, tout marche. Sous IE, le gif s’affiche mais n’est pas animé; le fait qu’une action soit déclenchée après bloque l’animation. Voici le javascript qui affiche le gif puis qui lance l’action :

 

document.getElementById("waitbar").style.visibility = 'visible';
document.getElementById('formliengeneration:linkpdf').onclick();

 

 

Solutions :

1- J’ajoute le javascript suivant à ma page xhtml:

document.forms['maform'].onkeypress =
new Function("{var keycode;if (window.event) keycode = 
window.event.keyCode;else if (event) keycode = 
event.which;else return true;if (keycode == 13) { 
document.getElementById('maform:validButton').click();
return false; } 
else  return true; 
}");

et ça marche.

Le problème venait du fait que JSF ne gère pas la validation automatique des formulaires par la pression de la touche ENTER. Cela marche avec Firefox, car celui-ci, depuis une mise à jour, s’en charge à la place du code javascript ci-dessous, qui résout le problème.

 

2- Il faut mettre ‘application/force-download’ en ‘type MIME’
et ‘attachment’ en ‘Content-disposition’
du coup; et Firefox et IE demandent ce que l’on veut faire du fichier

 

 

3-En fait, le gif n’est plus animé sous IE, car celui-ci considère qu’après le clic, on a changé de page, donc il arrête l’animation du gif en attendant la réponse.

Aucune solution pour les gif ; j’ai donc remplacé le gif par une animation flash faite avec un petit logiciel libre: e-anim
et voila, le tour est joué

P6SPY :

P6SPY est un projet Open-Source qui permet de contrôler les requêtes envoyées par un programme au SGBD. Nous allons voir ici comment l’installer de manière à voir les requêtes qui passent par le WS de l’AMUE.

Nous partons du principe que ‘apows.war’ (l’application Web contenant les WS de l’AMUE) est déployée sur un serveur Tomcat dans le dossier ‘apows’ du répertoire ‘webapps’.

Voici les étapes à réaliser pour installer de P6SPY :

1/ Télécharger le driver P6SPY (le .zip contient les fichiers p6spy.jar et spy.properties).

2/ Mettre le fichier p6spy.jar dans le répertoire ‘WEB-INF/lib’ d’apows

3/ Modifier le bean datasource du fichier webservices-SpringContext.xml d’apows comme suit :

<bean id=”dataSource”

class=”org.apache.commons.dbcp.BasicDataSource”>

<property name=”driverClassName” value=”com.p6spy.engine.spy.P6SpyDriver” />

<property name=”url” value=”UrlDeVotreSGBD” />

<property name=”username” value=”VotreUsername” />

<property name=”password” value=”VotrePassword” />

</bean>

4/ Placer le ‘spy.properties’ dans le répertoire ‘WEB-INF/classes’ d’apows

5/ Dans le spy.properties, vérifier les valeurs suivantes

               module.log = com.p6spy.engine.logging.P6LogFactory
               ...
               Realdrive r= oracle.jdbc.driver.OracleDriver
               ...
               appender= com.p6spy.engine.logging.appender.FileLogger
               logfile     =  Path vers webapps/apows/spy.log

6/ Ajouter les jar suivantes dans apows/ WEB-INF/lib :

commons-dbcp.jar

commons-pool.jar

Voila, P6SPY est installé. Vous pouvez lancer votre serveur puis voir l’ensemble des requêtes qui ont circulées dans le fichier spy.log (dont l’emplacement est défini à l’étape 5).

 

NB : Chaque requête est loguée 2 fois : une fois avec les paramètres de requêtes sous la forme ‘?’ et une fois avec les paramètres de requêtes qui apparaissent en clair. Ces 2 requêtes sont séparées par un |

Pour choisir les éléments à rapporter dans spy.log, il faut jouer avec les valeurs de ‘excludecategories’ dans spy.properties (ex : excludecategories=info, debug, result, batch, resultset)

Récupération des inscriptions dans un autre cursus :

La récupération des inscriptions d’un étudiant dans d’autres cursus n’était pas présente dans la ‘pré-version’ du Web Service. Aujourd’hui que nous avons la version finale, nous pouvons récupérer ces informations.

Pour récupérer les inscriptions d’un étudiant à des cursus externes nous avons besoin d’un proxy :

AdministratifMetierServiceInterfaceProxy monProxyAdministratif

Voici les objets et méthodes utilisés par l’intermédiaire de ce proxy :

recupererCursusExterne -> CursusExternesEtTransfertsDTO

puis on récupère les CursusExterneDTO dans un tableau avec la méthode getListeCursusExternes() sur le CursusExternesEtTransfertsDTO retourné précédemment. Il ne reste ensuite qu’à parcourir ces éléments et à créer la liste des inscriptions aux cursus externes, attribut du bean Etudiant.

 

Voici le code de la méthode complète pour récupérer les inscriptions :

CursusExternesEtTransfertsDTO ctdto = monProxyAdministratif.recupererCursusExterne(etudiant.getCod_etu());

CursusExterneDTO[] listeCursusExt = ctdto.getListeCursusExternes();

for (int i = 0; i < listeCursusExt.length; i++) {

Inscription insc = new Inscription();

CursusExterneDTO cext = listeCursusExt[i];

//on renseigne l’inscription:

insc.setCod_anu(cext.getAnnee());

insc.setLib_etb(cext.getLibEtablissement());

insc.setCod_dac(cext.getLibDiplome());

insc.setLib_cmt_dac(cext.getIntituleDiplome());

insc.setRes(cext.getTemObtentionDip());

//ajout de l’inscription dans la liste:

e.getLinscdac().add(insc);

}

Installation du Web Service de l’AMUE :

Voici la démarche à suivre pour installer le WebService de l’Amue et utiliser la librairie ‘apo-webservicesclient.jar’ dans son projet.

1/ déployer apows.rar dans Tomcat (qui sera ensuite présent dans webapps/apows).

2/renseigner ses paramètres de connexion (jdbcUrl, user et password) à Apogee dans ‘webservices-SpringContext.xml’ présent dans le répertoire ‘apows/WEB-INF/classes’

3/ ajouter le contexte du WS dans le fichier server.xml du répertoire ‘conf’ de Tomcat, ex :

<Context path=”/apows” docBase=”C:/esupdev/esupdev-2.5-esup-2.1.01/uPortal-quick-start/webapps/apows” crossContext=”true” reloadable=”true”/>

4/ ajouter la librairie apo-webservicesclient.jar dans son projet

 

5/ configurer le fichier configUrlServices.properties et le placer dans le répertoire ‘WEB-INF/classes/’ . Si Tomcat est en ‘http://localhost:8080’ une fois lancé, il n’y a rien a changer dans configUrlServices.properties

 

 

Nous pouvons maintenant utiliser le WebService dans notre projet. Exemple :

//récupération du cod_etu et du cod_nne à partir du cod_ind d’un étudiant :

EtudiantMetierServiceInterfaceProxy monProxyEtu = new EtudiantMetierServiceInterfaceProxy();

IdentifiantsEtudiantDTO idetu = monProxyEtu.recupererIdentifiantsEtudiant(null, etudiant.getCod_ind(), null, null, null, null, null, null, null, “N”);

etudiant.setCod_etu(idetu.getCodEtu().toString());

etudiant.setCod_nne(idetu.getCodNneInd() + idetu.getCodCleNneInd());

Revue du code

Pour ce projet, nous utilisons le plugin Jupiter pour faire de la revue de code.

Voici comment se déroule une session de revue de code avec cet outil :

  1. Phase individuelle : chacun des participants parcourt le code du projet et annote les sources avec des commentaires sur les problèmes qu’il identifie. A l’issue de cette phase, à chaque commentaire de revue de code est associé un type et un niveau de sévérité.
  2. Phase d’équipe : l’équipe de développement examine chacun des commentaires pour juger de leur pertinence et en affecter la résolution à un des membres de l’équipe (Charlie dans notre cas ;-) ). A l’issue de cette phase, chaque commentaire de revue de code est donc affecté à un développeur avec le type de résolution à appliquer.
  3. Phase de reprise : chaque développeur à qui des commentaires de revision ont été affecté traite le problème. A l’issue de cette phase, le statut de la révision est mis à jour (idéalement il doit être à “clos”).

Ce plugin s’appuie sur des fichiers xml pour stocker la révision du code. Il faut bien sur que ces fichiers soient stockés dans la repository svn pour pouvoir être échangés.

Plusieurs séances de révision de code peuvent ainsi s’enchaîner pendant la durée de vie du projet.

Utilisation des messages d’erreur JSF :

Jusqu’à aujourd’hui les erreurs possibles lors du remplissage des trois formulaires de l’application étaient gérées ‘manuellement’. Le contrôleur vérifiait les paramètres renseignés, et construisait un message d’erreur ainsi qu’un booléen ‘erreur’ en attribut. Puis on vérifiait, dans la page xhtml, la valeur du booléen ‘erreur’ : si il était ‘vrai’ on affichait le message en rouge.

 

Tout ceci a été modifié afin d’utiliser les fonctionnalités offertes par JSF. Grâce à cela, la méthode du contrôleur qui vérifie les champs est moins complexe car elle contient moins de boucle ‘if’ imbriquées (nécessaires à la construction d’un message d’erreur présentable dans une seule ‘String’) et la page xhtml voit ces trois lignes de code (contenant la condition d’affichage du message d’erreur dans un attribut ‘rendered’) nécessaire au message d’erreur simplifiées en une seule, très courte. De plus le contrôleur n’a plus besoin d’avoir les variables ‘String message’ et ‘boolean erreur’ en attribut car la page xhtml n’a plus besoin d’y accéder.

 

Voici un exemple du code obtenu pour un formulaire simple (1 seul champ):

La méthode du contrôleur :

public String chercher() {

String message = “”;

if (codetu != null && !codetu.equals(“”)) {

String codindetu = service.getCodIndFromCodEtu(codetu);

if (codindetu != null) {

return etatcivilcontroller.lienEnterNumero(codindetu);

}

message = “Etudiant ” + codetu + ” inexistant”;

FacesMessage messageX = new FacesMessage(FacesMessage.SEVERITY_ERROR, message, message);

FacesContext.getCurrentInstance().addMessage(null, messageX);

} else {

message = “Veuillez rentrer un identifiant.”;

FacesMessage messageX = new FacesMessage(FacesMessage.SEVERITY_ERROR, message, message);

FacesContext.getCurrentInstance().addMessage(null, messageX);

}

return View.CHERCHE_NUM;

}

L’affichage du message d’erreur dans page xhtml :

 

<h:form id=”formRechDossierWeb”>

<h:messages id=”champMessages” errorStyle=”color: red” />

Et voici le résultat pour un formulaire un peu plus complexe (3 champs) :

Messages d’erreur

 

Un point sur le ‘LookAndFeel’ :

Nous avions précisé dans les premiers post (‘Un point sur les facelets et JSF‘) de ce blog qu’il était possible de garder le ‘Look And Feel’ de l’application ‘MonDossierWeb’ d’origine ; nous allons apporter ici un peu plus de précisions.

En effet, si nous savions qu’il était possible de garder les mêmes class de style que dans l’application d’origine, il y a un point que nous n’avions pas abordé : le javascript.

L’application d’origine utilise par exemple du javascript sur l’action onMouseOver des lignes (<tr>) de ses ‘table’ pour les afficher en surbrillance lorsque l’on place la souris dessus. Exemple pour la page qui liste les inscriptions d’un étudiant:

<tr onMouseOver=”javascript:this.className=’uportal-background-highlight’”

onMouseOut=”javascript:this.className=’uportal-background-content’”>

Or, pour cette même page nous utilisons (dans la nouvelle version) une dataTable pour afficher le contenu d’une liste (‘linsciae’ la liste des inscriptions iae par exemple), attribut du bean ‘Etudiant’. Nous n’utilisons donc pas la balise <tr> puisqu’elle est générée automatiquement en utilisant les balises ‘column’ de la dataTable. Exemple :

<t:dataTable id=”tableiae” value=”#{etudiant.linsciae}” var=”ins” cellpadding=”5″ border=”0″ width=”100%”>

<h:column>

<f:facet name=”header”><u>Année</u></f:facet>

<h:outputText value=”#{ins.cod_anu}”/>

</h:column>

<h:column>

<f:facet name=”header”><u>Code</u></f:facet>

<h:outputText value=”#{ins.cod_etp}”/>

</h:column>

<h:column>

<f:facet name=”header”><u>Vers.</u></f:facet>

<h:outputText value=”#{ins.cod_vrs_vet}”/>

</h:column>

<h:column>

<f:facet name=”header”><u>Etape</u></f:facet>

<h:outputText value=”#{ins.lib_etp}”/>

</h:column>

</t:dataTable>

Heureusement la librairie tomahawk fournit une ‘dataTable’ plus évoluée que la librairie jsf. La dataTable tomahawk fournit par exemple les attributs ‘rowOnMouseOver’ et ‘rowOnMouseOut’ chargés de remplacer ‘onMouseOver’ et ‘onMouseOut’ de la balise <tr>. Il ne reste ainsi qu’à modifier :

<t:dataTable id=”tableiae” value=”#{etudiant.linsciae}” var=”ins” cellpadding=”5″ border=”0″ width=”100%”>

En

<t:dataTable id=”tabledac” value=”#{etudiant.linscdac}” var=”insd” cellpadding=”5″ rendered=”#{etudiant.existeInsDac}”

rowOnMouseOver=”javascript:this.className=’uportal-background-neutral-light’”

rowOnMouseOut=”javascript:this.className=’uportal-background-content’”>

pour obtenir le même rendu que dans l’application d’origine.