Bonjour.
J'envoie ce billet pour informer mes chers lecteurs (s'il y'en y'a :-)) que ce blog n'est plus maintenu et que j'ai migré vers un autre blog (hébergé sur développez.com) don voici l'adresse:
http://blog.developpez.com/index.php?blog=174
Merci et on se retrouve dans mon nouveau blog !
Tuesday, December 4, 2007
Déplacement de blog
Friday, November 16, 2007
Drag'n'Drop avec RichFaces
Bonjour: Encore un petit exemple avec RichFaces.
Cette fois-ci, il s'agit de réaliser une petite application mettant en oeuvre le drag and drop offert par RichFaces.
C'est une simple application composée d'une seule page et qui simule l'activité d'achat en ligne: quleques articles et un paneau. Pour acheter un article, il suffit de le dragger et le dropper dans le paneau.
Attaquons sans tarder la couche métier de notre application.
On commence par les entités (1 seul dans ce cas-ci):
- L'objet Item représente un article. Il contient juste un identifiant, un nom et un prix.
package model;
public class Item {
private String name;
private Long price;
private Long id;
public Item() {
}
public Item(String name, Long price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getPrice() {
return price;
}
public void setPrice(Long price) {
this.price = price;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
Passons maintenant au contrôleurs JSF. On en a deux:
- ItemCtrl: Un simple pojo qui expose une liste d'Items.
- CartCtrl: Contient lui une liste d'Items qui représente les articles achetés jusque là ainsi qu'un champ price qui contient le prix total des articles achetés.
De plus, c'est ce contrôleur qui gère l'evènement drop généré lorsque l'on dépose un article sur le paneau.
package control;
import java.util.ArrayList;
import java.util.List;
import model.Item;
public class ItemsCtrl {
private List<item> items = new ArrayList<item>();
public ItemsCtrl() {
items.add(new Item("Montre", 50L));
items.add(new Item("Table", 450L));
items.add(new Item("Chaise", 150L));
items.add(new Item("Moquette", 250L));
items.add(new Item("Lit", 750L));
items.add(new Item("Armoire", 1050L));
items.add(new Item("Ordinateur", 750L));
items.add(new Item("Imprimante", 90L));
}
public List<item> getItems() {
return items;
}
public void setItems(List<item> items) {
this.items = items;
}
}
Rien de spécial à dire à propos de cette classe ;-) (juste un détail, dans le constructeur, j'ai ajouté quelques articles fictifs pour égayer un peu l'application !)
Maintenat, le code de CartCtrl:
package control;
import java.util.ArrayList;
import java.util.List;
import org.richfaces.event.DropEvent;
import model.Item;
public class CartCtrl {
private List<item> items=new ArrayList<item>();
private Long price=0L;
public void onDropItem(DropEvent e) {
Item i = (Item) e.getDragValue();
items.add(i);
price += i.getPrice();
}
public List<item> getItems() {
return items;
}
public void setItems(List<item> items) {
this.items = items;
}
public Long getPrice() {
return price;
}
public void setPrice(Long price) {
this.price = price;
}
}
Le seul point à expliquer ici est la méthode onItemDrop.
Cette méthode ne retourn rien (void) et accèpe un paramètre de type org.richfaces.event.DropEvent
qui contient toutes les informations relatives à un évènement Drag and Drop.
En particulier, on a le champ dragValue (Object) qui contient l'objet qu'on a déplacé et laché au dessus du paneau. Ici, c'est un Item. Dèslors, on l'ajoute à la liste des articles achetés et on incrémente le prix total des achats.
Passons smaitnenant à la couhe présentation.
Pour afficher la liste des articles, j'ai décidé d'utiliser le composant DataGrid de RichFaces qui ressemble à DataTable mais qui affiche les données exactement comme le composant PanelGrid de JSF:
Voici ce que ça donne:
<rich:dataGrid value="#{itemsCtrl.items}" var="item" columns="3">
<h:panelGrid border="0" columns="2">
<h:outputText value="Nom: " />
<h:outputText value="#{item.name}" />
<h:outputText value="Prix: " />
<h:outputText value="#{item.price}" />
</h:panelGrid>
</rich:dataGrid>
on va maintenant rendre les éléments draggables. Pour ce faire, il suffit d'ajouter le composant
Dans notre cas, on va placer le panelGrid sur lequel on itère dans le composant a4j:outputPanel (dragSupport impose quelques limitations sur le conteneur, et il se trouve que outputPanel les satisifait). On ajoutera ensuite dragSupport dans le outputPanel, ce qui donne:
<rich:dataGrid value="#{itemsCtrl.items}" var="item" columns="3">
<a4j:outputPanel layout="block" style="cursor: move">
<rich:dragSupport dragType="item" dragValue="#{item}" />
<h:panelGrid border="0" columns="2">
<h:outputText value="Nom: " />
<h:outputText value="#{item.name}" />
<h:outputText value="Prix: " />
<h:outputText value="#{item.price}" />
</h:panelGrid>
</a4j:outputPanel>
</rich:dataGrid>
Comme principaux paramètres, dragSupport prend:
- dragType: une chaine qui identifie le type de l'élément. C'est surtout utile pour pouvoir discerner entre plusieurs types d'élements draggables. Ici, on en a qu'un seul, et on le nomm item.
- dragValue: la valeur de l'élément draggé. C'est cette valeur là qui sera récupéré dans DropEvent .getDragValue (cf plus haut). Ici, on met l'Item courant.
Comme pour le drag, on définit un etelle zone en incluant le composant dropSupport:
<a4j:outputPanel layout="block">
<rich:dropSupport acceptedTypes="item"
dropListener="#{cartCtrl.onDropItem}"
reRender="boughtItems, totalPrice" dropValue="x"></rich:dropSupport>
<h:graphicImage url="/pics/shopping_cart.png"></h:graphicImage>
</a4j:outputPanel>
En gros, il s'agit d'une image à l'intérieur dans outputPanel 'pour les même raisons que pour le dragSupport).
Les attributs de dropSupport sont:
- acceptedType: un liste de types d'élements acceptés par cette zone. Ici, on ne a qu'un seul qui est item (cf attribut dragType du composant dragSupport).
- dropListener: la méthode d'un managed bean qui sera appelée lorsque le drag and drop est terminé (cf CartCtrl.onDropItem).
- reRender: les identifiants des composants à redessiner à la réception de la réponse de la requête générée par le drop.
<rich:dataList id="boughtItems" value="#{cartCtrl.items}" var="item">
<h:outputText value="#{item.name}" />
</rich:dataList>
<h:outputText id="totalPrice" value="Prix total: #{cartCtrl.price}" />

voilou ! C'est un peu long parceque on est passé par un exemple plus ou moins réaliste et pratique, mais c'est hyper-simple dans le fond !
Voici un petit shot de l'application:
Saturday, November 10, 2007
Configuration d'eclipse WebTools 2 pour JSF
Afin de pouvoir utiliser les fonctionnalités de WTP 2, il faut le configurer avec une implémentation JSF.
J'ai réalisé deux petites démos avec Wink montrant ce processus que vous pouvez consulter dans mon espace developpez.com. Les démos sont dans cette page.
Quelques remarques vite-faites:
- Il vous faut eclipse 3.3.1.1, sinon, vous risquez le suicide avec les OOME PermGenSpace.
- Il vous faut wtp 2.0.1 (pas le 2.0), sinon vous risquez encore une fois le suicide :-)
Friday, November 9, 2007
GuessGame version RichFaces
On y arrive enfin !
Sans plus tarder, attaquons la chose.
N.B: Je vais passer l'étape de configuration de RichFaces (voir post précédent).
Je vous rappèle donc le principe du jeu: Au départ, l'application génère un nombre aléatoire entre 1 et 100. L'utilisateur essaie de deviner ce nombre à travers un textbox. à chaque essais, l'application vous informe si c'est trop grand, trop petit ou si c'est la bonne réponse.
On commence par le backing bean de notre jeu qui va génerer le nombre aléatoire et ensuite vérifier les essais du joueur.:
public class GameBean {
private int magic;
private Random random;
private String guess;
private String message;
public GameBean() {
random = new Random();
reset();
}
private void reset() {
magic = random.nextInt(100) + 1;
guess = "";
message = "...";
}
public String check() {
int x = 0;
try {
x = Integer.parseInt(guess);
if (x < 1 || x > 100)
throw new Exception();
} catch (Exception e) {
message = "Entrée non valide";
return null;
}
if (x < magic) {
message = "Trop petit !";
} else if (x > magic) {
message = "Trop grand !";
} else {
message = "Excellent ! Le nombre magique était " + magic;
}
return null;
}
public int getMagic() {
return magic;
}
public String getGuess() {
return guess;
}
public void setGuess(String guess) {
this.guess = guess;
}
public String getMessage() {
return message;
}
}
Voici rapidement de quoi il s'agit:
- Le champ magic (int) va contenir le nombre à deviner.
- Le champ random (java.util.Random) servira à générer les nombres aléatoires.
- Le champ guess (String) servira à receuillir les essais de l'utilisateur. Normalement, il devrait être de type int combiné avec un converter dans la page JSF, mais bon, j'ai omis ça pour simplifier la chose.
- Le champ message servira à contenir la réponse de l'application suite à un essai du joueur (trop grand, trop petit, etc.)
- La méthode privée reset() sera appelée à l'initialisation du jeu pour générer le nombre aléatoire.
- La méthode check() est une action JSF (type de retour String, sans paramètres) quis era appelé à chaque entrée utilisateur pour la vérifier.
N.B: check retourne toujours null, et ce pour rester dans la même page. - Les méthodes restantes ne sont que des getters et des setters pour exposer nos champs à l'EL (aux pages JSF).
Normalement (sans Ajax), nous aurions déclaré dans <f:view > un élément de type <h:form > avec un inputText la dedans bindé avec notre #{guessBean.guess} ainsi qu'un outputText bindé avec #{guessBean.message} qui affichera le résultat, un truc de ce genre:
<h:form>
<h:inputText value="#{gameBean.guess}" />
<h:outputText value="#{gameBean.message}" />
<h:commandButton value="Check" action="#{gameBean.check}" />
</h:form>
En cliquant sur le commandButton "check", le formulaire sera envoyé et traité par JSF, ce qui implique entre autre que gameBean.guess se verra affecter la valeur entrée dans le champ texte. Ensuite, la méthode gameBean.check() à sera appelé qui va mettre dans le champ message le résultat de la vérification et retournera null. JSF retournera la main alors à la même page qui sera rendu à nouveau mais avec le message adéquat.
Nous allons maintenant ajaxifier la chose avec RichFaces (ou plus exactement avec Ajax4Jsf).
Dans une première passe (et là, c'est vraiment magique ;-)), on se contente de remplacer le composant form de JSF par celui d'ajax4jsf, comme ça:
<a4j:form>
<h:inputText value="#{gameBean.guess}" />
<h:outputText value="#{gameBean.message}" />
<h:commandButton value="Check" action="#{gameBean.check}" />
</a4j:form>
N.B: l'uri qu'il faut importer pour utiliser les comosants a4j est:
Relançons l'application.
A première vue rien ne se passe: suite à un clic sur le commandButton, absolument rien ne se passe ... mais en fait si ! Pour s'en convaincre, il suffit d'ajouter un simple :
System.out.println("check "+guess);
au tout début de GameBean.check().
Réessayez de nouveau ... et vous remarquerez que chaque fois que l'on appuie sur le commandButton, une ligne telle que celle-ci s'ajoute dans la console (d'eclipse par exemple):
check 45
check 23
Explication ? <a4j:form> intercepte tout submit déclenché par un de ses fils (ici, le commandButton) et le traduit en requête ajax vers le serveur où elle sera traité.
Mais alors, pourquoi le message ne change pas ?
C'est simple, il suffit d'indiquer à <a4j:form> quels composants il faut re-dessiner à la reception d'une réponse ajax. Ce comportement est plus qu'il y'a de naturel, autrement, on devrait re-dessiner tout faute de savoir qu'est ce qui a changé, ce qui revient à un submit http classsique et non plus Ajax.
Notre code devient donc:
<a4j:form reRender="out" >
<h:inputText value="#{gameBean.guess}" />
<h:outputText value="#{gameBean.message}" id="out" />
<h:commandButton value="Check" action="#{gameBean.check}" />
</a4j:form>
J'ai ajouté :
- l'attribut reRender="out" dans <a4j:form>
- L'attribut id="out" dans <h:outputText>
Ce qui tout naturellement veut dire "re-dessiner le composant dans l'identifiant est out à lae reception d'une réponse ajax".
N.B: reRender n'est pas limité à un seul identifiant, et peut prendre une liste d'attributs à re-dessiner, comme par exemple reRender="out, x, y, z".
En relançant l'application avec ces modifications, on aura notre guess-game version AJAX !
Pour approfondir la chose, vous pouvez essayer d'ajouter un compteur trials qui indique au fur et à mesure combien d'essaies le joueur a fait + un bouton rejouer qui ne s'affiche que lorsque la réponse est bonne (le second point, je vous le dis d'avance, est un casse-gueule :-) ... j'expliquerais pourquoi dans un prochain post).
Saturday, November 3, 2007
Say Hello Version RichFaces
Bonjour.
Chose promise, chose dû (voir post précédent) ... enfin, presque: au lieu du célèbre GuessGame, on va démarre avec un truc plus simple : le non moins célèbre SayHello.
Donc, il s'agit ici de réaliser une petite application JSF + JBoss RichFaces qui se contente de récupérer un nom entrée par l'utilisateur pour ensuite le saluer (Hello $nom).
Pour commencer, dans eclipse Europa + WTP 2.0.1, il faut créer un projet "Dynamic Web Project" en prensant soin d'unclure dans les librairies du projet les 3 fichiers jars de Rich Faces 3.1.2 GA téléchargeables ici.
Ajaxifier son application JSF avec RichFaces revient juste à ajouter ces 3 fichiers jars dans le classpath de l'applciation ainsi qu'ajouter ces quelques lignes dans son web.xml (juste après <display-name>).
<filter>
<display-name>RichFaces Filter</display-name>
<filter-name>richfaces</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>richfaces</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
Attaquons maintenant le jeu. On commence par créer un simle POJO (le managed bean) qui servira à stocker le nom saisie par l'utilisateur:
public class HelloBean {On déclare ensuite ce bean dans faces-config.xml pour qu'il soit accessible à nos pages:
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<managed-bean>On crée ensuite une première pages (index.jsp) qui se contente de "forwarder" vers la page JSF:
<managed-bean-name>helloBean</managed-bean-name>
<managed-bean-class>HelloBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<jsp:forward page="hello.jsf" />Enfin, on arrive aux choses sérieuses: du JSF et de l'AJAX. Dans la page hello.jsp, et à l'intérieur de l'élément view:
<h:outputText value="Name :" />Toute la magie de la chose est réalisée par le <a4j:support>. Il permet d'ajaxifier n'importe quel composant JSF standard. Ce composant est très flexible et a de nombreux usages, mais dans ce cas particulier, on l'a utilisé par capturer l'évènement onchange (javascript), formuler une requête AJAX et redessiner le composant outputText (reRender="greeting") à la reception de la réponse de cette requête. C'etait le comportement côté client. Côté serveur, RichFaces s'occupe de décoder la requête AJAX, mettre à jour le champ "name" de notre managed bean et formuler la réponse.
<h:form>
<h:inputText value="#{helloBean.name}">
<a4j:support event="onchange" reRender="greeting" />
</h:inputText>
</h:form>
<h:outputText id="greeting" value="Hello #{helloBean.name} !" />
C'etait un aperçu rapide sur la simplicité de la puissance de RichFaces. Je suis en train de rédiger un tutoriel plus détaillé sur RichFaces que je publierais ensuite dans mon espace de Développez.com.
Wednesday, October 31, 2007
RichFaces est Cool !
Tout est dans le tire: RichFaces est cool, plus que cool !
C'est un peu tard pour le dire, mais malheureusemnt, ce n'est que là que j'ai eu l'occasion de travailler avec :-(
Sinon, sa configuration est simple (quelques jars dans le WEB-INF\lib) et quelques lignes dans le web.xml, et hop, ça fonctionne !
Mais le plus important, c'est son utilisation: j'avais déjà quelques notions en AJAX et je sais en gros de quoi il s'agit. C'est pour ça que j'avais des doutes quant au jeux de composants ajaxifiés de JSF. Mais après quelques petites applications réalisés avec RichFaces 3.1.2 GA, je ne trouve plus de noms de oiseaux pour me traiter avec ! C'est simple, c'est court, c'est solide et c'est beau !
De plus, et là je tiens à remercier la section de rédaction de la documentation de JBoss, le Getting Started de RichFaces est vraiment bien fait, à l'inverse de la documentation de nombreux autres frameworks et jeu de composants ... je pense notamment à celui d'ICEfaces avec leur tutoriel d'introduction (TimeZone application) : Bravo les gars ! Ce tutoriel là m'a convaincu de laisser tomber ICEfaces malgré que ca m'a l'air bien fait lui aussi.
Je compte prochainement rédiger un petit tuto d'introduction à RichFaces (le célèbre Guess Game que je viens de finir cet après midi). Restez à l'écoute !
P.S. : Jetez donc un coup d'oeil sur leur live demo ... Je suis sûr que vous tomberez sous le charme.
Tuesday, October 30, 2007
Designers vs. Developers, Declaration vs. Procedure
Silence messieurs ! Gavin a parlé !
Voilou, dans son blog, Gavin King (le créateur d'Hibernate, architecte principal de JSF, membre du comité à l'origine de JPA, Seam, etc.) a posté pour parler de l'un des aspects les plus anciens et les plus problématiques du développement web en général et Java en particulier: la couche présentation.
Le problème principal est le suivant: qui devrait réaliser cette couche ?
- Les designers ? impossible, à moins de les apprendre à travailler avec la technologie utilisée (JSP/Java, PHP, etc.)
- Les programmeurs ? Oh ... et obtenir un résultat moche !
- Les hybrides (programmeurs/designers) ? Difficile de manier à la fois l'art de la progrmmation et l'art du web design ...
- Les deux ? C'est la pire des possibilités à mon avis ... et ça nécessite que chaque partie connaisse les ficelles des autres ... sinon, on risque de casser le design avec des bouts de code mal placés ou de casser le code avec des bouts de html mal placés ...
On n'exprime que son besoin, c'est à dire un menu qui permet de sélectionner un seul élément.<h:selectOneMenu value="#{pas important pour le moment}">
<f:selectItem itemLabel="label" itemValue= "valeur"/>
:
:
</h:selectOneMenu>
Une telle page (ne contenant que ce genre de déclaration) peut parfaitement être réalisé par un développeur. Après, si on veut rendre la chose plus zolie, on n'a qu'à ajouter quelques attributs dans les composants JSF pour faire le lien avec des styles CSS. C'est alors aux designers de préparer les styles, et hop !
C'est d'ailleurs la bonne architecture, même pour une page html: la page ne doit contenir que le contenu (sémantique) tandis que la mise en forme va dans les CSS.
Bref, j'explique comme une patate. Jetez plutôt un coup d'oeil sur ce qu'en dit Gavin.
Le sang coule !
Voici ce que j'appèle un débat enragé ! C'est incroyable comment une simple refléxion posée par une personne dans son blog peut faire couler du sang, euh ... de l'encre !
En gros, c'est une question simple qu' a posé Nati Shalom dans son blog: "Why most large-scale Web sites are not written in Java ?" ou en français "Pourquoi les plus grands sites ne sont pas écrits en Java ?".
Pour appuyer ses dires, il a inclu un zoli tableau généré des statistiques de High Scalability et qui est représenté dans l'image ci dessous:
Mais la réaction des internautes a été violente ... jugez en par vous même !
Nati Shalom Blog.
Eclipse Europa, enfin utilisable !
Ouf ! Les gars d'eclipse viennent enfin de fixer le maudit problème du Out of memory et PermGen Space.
Je suis actuellement en train de travailler sur eclipse depuis plus d'une heure et devinez quoi ? Pas de plantage ! C'est tout bizarre, mais je m'y ferais :-). Et le comble, c'est que le mesquin n'a que 512Mo de RAM ! et il bosse sur WTP 2 en plus !
Eclipse peut être téléchargé ici : http://www.eclipse.org/downloads/.
Monday, October 29, 2007
Defective C++
Je sais que je risque de me faire lapider pour ça, mais la tentation est trop forte ...
Voila l'expression écrite des tous mes sentiments les plus secrets et tabous à l'égard de la monstruausité qu'est le C++ :
http://yosefk.com/c++fqa/defective.html
C'est un article en anglais, qui dissique froidement et sans la moindre pitié les moindres défauts du C++ sans toutefois plonger dans la haine aveugle, c'est assez technique et agrémenté de boutts de code pour apputer ses dires.
Etant un Javaïste jusqu'à l'os, je ne peux que remercier le ciel d'avoir déniché un tel article !
Régalez vous en (ou l'inverse, ça dépend bien sûr de quel camp on est !)

