Friday, April 10, 2009

Zenika Wicket Contest / Concours Wicket Zenika

It's exceptional but I wrote this post in french. It's about a contest which proposed to developed a tiny Apache Wicket project with another framework. I tried to implement it with SmartGWT.

Bon et bien voilà : je livre mon appli ZenContact migrée en GWT. Je vous préviens, je ne vais pas trop mâcher mes mots. L'objectif du concours est assez clair : refaire une petite appli de gestion de contacts réalisée à l'occasion d'une présentation Wicket au Paris JUG; le tout avec un petit défi en plus car cette présentation menée par Zenika n'a duré qu'une heure.

Bref, devant l'enthousiasme général, j'ai entrepris de la refaire en GWT. Et comme il fallait aller vite, j'ai choisi de m'appuyer sur des outils et API pour avoir le moins à coder possible. Je fixe rapidement la stack de travail : Eclipse 3.4, Maven 2, SmartGWT. Bon, c'est parti! New maven project -> template gwt. Je teste l'application générée par le plugin Maven. Jusque là tout est OK. Un bonheur.

Je n'ai jamais travaillé avec SmartGWT mais ça a l'air assez riche. Je garde toujours firefox en arrière plan avec la démo de l'API. Je copie-colle des bouts de code et en 3 heures j'ai mon formulaire, mon tableau éditable, le drag and drop, le date picker et tout le reste. Pas mal... Je décide d'arrêter là pour le premier jour.

Le code du tableau triable/editable avec drag and drop : impressionnant non?
contactGrid = new ListGrid();
contactGrid.setWidth(300);
contactGrid.setHeight(224);
contactGrid.setAlternateRecordStyles(true);
contactGrid.setShowAllRecords(true);
contactGrid.setCanReorderRecords(true);
contactGrid.setCanDragRecordsOut(true);
contactGrid.setDragDataAction(DragDataAction.COPY);
contactGrid.setDataSource(this.datasource);
contactGrid.setAutoFetchData(true);
contactGrid.setCanEdit(true);
contactGrid.setEditEvent(ListGridEditEvent.DOUBLECLICK);
contactGrid.setEditByCell(true);


Le lendemain, je passe à l'intégration des pages de l'application Wicket d'origine dont je reprends les 3 fichiers html. Premier problème : j'ai trois pages. Ca fait 3 modules GWT. Pour rappel, pour les petites applications GWT, tout se met dans un seul et même module. Tant pis, je conserve les pages; ça sera l'occasion de me lancer dans la communication entre modules, je ne l'ai jamais fait. Pour cela, j'opte pour une solution pipotesque qui consiste par passer par un cookie. En principe, tout doit rouler car j'ai repéré que SmartGWT travaille tout en JavascriptObject transformables en chaines JSON. Vous voyez où je veux en venir... Et c'est là que les ennuis commencent. Impossible de convertir simplement ma datasource. Je commence à chercher dans la documentation SmartGWT... ah, j'oubliais : il n'y en a pas en dehors de la démo! Je regarde donc du côté de l'API. Le moins que l'on puisse dire, c'est que ça ne manque pas de méthodes. C'est riche, très riche, tellement riche que je ne sais pas quoi en faire. Les petits tours dans le code source me refroidissent vite fait car SmartGWT utilise JSNI à outrance dans la mesure où il ne fait que du wrapping de javascript. Après quelques heures, je trouve la solution. Fin de l'épisode du jour.

Je laisse le projet de côté pendant quelques jours avant de m'y remettre pour le packager. Je reteste quand même vite fait avant. Et là : deuxième problème. Mon tableau n'affiche plus de données. Bizarre. Je m'arrache les cheveux à coup de debugger. Tout a l'air correct.... Je n'y comprends rien. Je recherche du côté de la démo de SmartGWT et me rends finalement compte d'une ligne récurrente dans pas mal d'exemples de code. Un « setAutoFetchData(true) ». Je teste mon code avec ça : bingo! Ca marche! Je réalise à présent qu'en plus d'être trop riche, SmartGWT n'est pas dans un état fini. Je m'imagine dans un contexte de production à chercher ce genre de bug... Bon,avec tout ça, je n'ai pas eu le temps de packager. J'arrête les frais pour aujourd'hui.

De retour sur le code, je redécouvre GWT (je n'en fait plus depuis quelques mois). Pour rappel, 1 module compilé = 1 emplacement pour les fichiers générés. Mais avec mes trois pages, ça ne va pas du tout. Par exemple, WelcomePage.html se retrouve dans tous les répertoires et, comme les liens entre les pages restent relatifs à chaque module, je ne peux pas passer d'un module à l'autre. Bref, je recherche comment faire sur le forum GWT et implémente une petite solution assez simple me permettant de ne travailler qu'avec un seul module.

Enfin, c'est fini! L'application n'est pas complètement bouclée mais je n'irai pas plus loin. Il est d'ailleurs temps d'écrire mes conclusions sur le projet.

Tout d'abord, j'ai été impressionné par les progrès d'intégration des développements GWT dans Eclipse. Cela est clairement dû à l'intégration Maven. Et oui, Maven, on peut dire ce qu'on veut dessus mais c'est tout de même l'esperanto de l'IDE.
Ensuite, j'ai été surpris par la rapidité de prise en main de SmartGWT. La démo est bien faite même si le code source montré n'est pas complet et qu'il faut vite télécharger la suite. Ce framework propose des fonctionnalités très poussées. C'est très agréable... au début seulement. Rapidement, on voit bien que l'API est trop riche. Ca part dans tout les sens. Elle n'est pas guidante et c'est dommage car le code produit au final est plutôt satisfaisant. Cela provoque une courbe de développement chaotique. Au premier bug, c'est l'explosion du temps de développement et la chute de cheveux assurée. Et par dessus cela, comme on est sous GWT, le temps de compilation est (très long) et chaque test devient un calvaire.

Alors, quid de la solution GWT par rapport à la version Wicket? Et bien vous l'aurez compris, je déconseille l'utilisation de SmartGWT pour le moment. L'API n'est pas mature. Elle a toutefois l'intérêt d'être très bling-bling pour les démos. Pour ce qui est de GWT, l'intérêt se situe sur son orientation « client centric ». Et oui, l'application dans sa version actuelle tourne sur un simple serveur Apache lorsque Wicket demande un Tomcat. Mais quelle lenteur ce compilateur Javascript/Java! Finalement, cette expérience confirme l'avis que m'était fait sur ces deux frameworks :
GWT est un excellent framework pour les applications à interactivité utilisateur forte. Ses capacités de manipulations des objets DOM et de gestion des évènements du navigateur sont excellentes.
Dans le cas d'une application de gestion classique, Wicket est un choix bien plus judicieux. L'utilisation des « Model », la gestion des conversations, le développement loin de javascript (qui est quand même un vrai langage de merde!), l'intégration Spring, l'internationalisation, le code source clair sont autant de points qui font du développement avec Wicket un vrai bonheur.

Pour finir en quelques mots : Wicket c'est une Renault. Ca marche plutôt bien au quotidien. GWT, c'est une Ferrari. C'est beau une Ferrari. La super éclate le week-end. Mais pour aller chercher le pain, ce n'est pas forcément le mieux.

Télécharger le projet compilé (à dézipper + trouver le WelcomePage.html) : zencontact_gwt.zip
Télécharger le code source : zencontact_gwt_src.zip

Wednesday, April 08, 2009

Why can I access to port 8080 only from localhost on Ubuntu?

To achieve the previous post, I had some problems today to access to my tomcat server from another machine. Ping OK but telnet 8080 KO... Humm, this smells firewall rules. Bingo! I didn't considered iptables as a firewall but it's one!

So, if you are in a secure network area, you can disable it temporarily with the following command :
sudo iptables -F
You can go further by reading this how-to page : https://help.ubuntu.com/community/IptablesHowTo

Tuesday, April 07, 2009

TCP Port 80 blocked on Ubuntu

While working on project, I had to bind my Tomcat to port 80 (instead of deploying an Apache and configuring its mod_jk). But, as you should know, Unix systems contains default security rules. Ports below 1024 are only allowed to the root user. Humm... it was time to work with iptables!

The following commands would show you how to add a rule to redirect request on port 80 to port 8080 and how to remove this rule.

Adding a rule :

sudo iptables -t nat -I OUTPUT --src 0/0 --dst [YOUR_IP_HERE] -p tcp --dport 80 -j REDIRECT --to-ports 8080

Saving it :

sudo iptables-save

Listing rules :

sudo iptables -t nat --line-numbers -n -L

This will show rules ordered by REDIRECT, PREROUTING, POSTROUTING and
OUTPUT. Each line start wil a number.

Deleting a rule :

sudo iptables -t nat -D [REDIRECT, PREROUTING, POSTROUTING or OUTPUT] number

Ex : sudo iptables -t nat -D OUTPUT 1