19 novembre 2009
Imprimer ce billet

Devoxx – Jour 2 – Google App Engine

Toujours sur le sulfureux sujet du Cloud Computing mais cette fois-ci côté PaaS (Platform as a Service), une session spéciale Google App Engine nous est proposée avec l'idée de développer une vraie application de gestion sur le cloud et de voir les difficultés rencontrées pendant le développement. Et pour corser le tout, 3 technos front-end seront en concurrence : Spring MVC, JSF 2.0 (très early adopter pour le coup) et GWT 1.7.

Le projet

Tout d'abord, la home page du projet Swag Swap se trouve à cette url. Elle regroupe toutes les informations utiles, les liens vers les différents projets par technos, un espace google-moderator pour poser des questions aux speakers (et réponses en live).

Fonctionnellement, le projet est un espace de vente d'objets divers et variés avec notation de ces objets, commentaires associés, etc. Côté administration, on pourra gérer les objets (ajouter, modifier ou supprimer) et avoir accès à d'autres fonctionnalités. On illustre ainsi GAE par un projet plus concret que le basique Helloworld. A gauche l'apparence de l'application GWT (single page interface) et à droite celle des applications Spring MVC et JSF 2.0 :

gae_swagswap

Fondamentaux

Avant de rentrer dans le vif du sujet, quelques rappels sur l'architecture de GAE nous sont faits. Ainsi, GAE est de type PaaS : aucune installation hardware ni d'infrastructure mainframe, tout est géré par Google qui hébergera notre application sur ses serveurs et la dimensionnera à l'infini si besoin (attention aux quotas ;) ). La base de données utilisée est BigTable, base de données non relationnelle distribuée, scalable, transactionnelle et schema-less ; le tout accessible par les APIs JDO et JPA.

Les détails techniques sont tout de suite évoqués avec entre autres :

  • des requêtes limitées à 30 secondes,
  • pas de serveur push,
  • pas de threads,
  • un système de fichiers en lecture seule,
  • des whitelisted classes (plusieurs classes du JDK non disponibles sous GAE),
  • impossibilité de créer/mettre à jour plus d'une entité au sein d'une transaction.

Ces quelques lignes peuvent évidemment faire reculer violemment un développeur Java et c'est bien là l'idée de cette conférence : n'ayez pas peur ! La preuve : leurs applications fonctionnant sous GAE et sous 3 frameworks web différents ! Quelques adaptations sont néanmoins nécessaires.

Pour ceux qui souhaitent approfondir la persistance dans GAE,je vous renvois vers un précédent article qui traite parfaitement le sujet.

Implémentations

Côté architecture, on retrouve globalement ce que l'on connait déjà dans notre écosystème JEE à savoir :

  • Spring 3.0,
  • JDO,
  • Une couche service partagée par toutes les applications,
  • RESTful,
  • Spring MVC / JSF 2.0 / GWT 1.7,
  • Build, tests et déploiement avec Ant,
  • Pour le debug, l'appengine development server pour SMVC et JSF et le Hosted Mode pour GWT,
  • Gestion des projets avec google-code (issues, version control, release management).

Nous sommes donc en face d'une application 3-tiers standard. Les POJOs sont de simples POJO Spring. La couche DAO utilise un JdoTransactionManager mappé avec un PersistentManagerFactory connecté sur le datastore d'appengine (org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory).

La première chose qui saute aux yeux est bien sûr l'utilisation de JDO. Pourquoi ce choix (question du modérateur) ? Parce que la majorité des tutoriels s'appuie sur JDO. Il est tout à fait possible d'en trouver avec JPA mais ils sont globalement moins nombreux. D'où le choix de JDO. Avec toutes ces présentations Devoxx autour de JPA 2, cela surprend...

Nous nous retrouvons ensuite rapidement dans Eclipse avec de nombreux exemples de codes, d'injections, de configuration... La conférence prend rapidement un air de présentation de Spring MVC avec la configuration par annotations et entre autres les URI Templates de RESTful Spring MVC 3. Pour les habitués de Jersey, l'idée est la même (paramètres dans le path de l'URL) mais le nom des annotations change un peu. Voici un exemple d'utilisation :

@RequestMapping(value="/edit/{id}", method=RequestMethod.GET)
public String editHandler(@PathVariable("key") Long key, Model model) {
  SwagItem swagItem = itemService.get(key, true);
}

Suivront ensuite quelques screenshots de l'utilisation de MemCache et d'envoi de mails avec Task Queue, la gestion de transactions, la gestion d'Entity Groups... Le tout est bien sûr testé unitairement. Nous passerons sur ces points, de nombreuses documentations existent un peu partout sur la toile.

Le tour complet est fait, mais maintenant on veut savoir...

Problèmes rencontrés

Bon alors, quels sont les problèmes que vous avez rencontrés ?

Et bien il y en aura eu, du simple à résoudre au plus complexe qui demande de bien écrire ses APIs ou de paramétrer légèrement sa configuration.

Côté back-end, la mise à jour d'une seule entité au sein d'une transaction peut évidemment poser de gros problèmes concernant l'insertion de nombreuses entités mais aussi concernant un rollback de transaction. Pas de réelle solution, à part programmer à la main un rollback sur des objets déjà commités.
Concernant l'impossibilité d'écrire sur le disque, la base de données contient un champs BLOB qui contiendra les images des articles à vendre.

Spring MVC a posé des soucis concernant quelques requêtes Ajax et surtout celles de rating qui requièrent un utilisateur logué. Dans ce cas, la page de connexion spéciale Google (au passage non configurable) apparaît et, une fois logué, la redirection se fait sans les paramètres d'URL. On perd donc le fait que l'on venait de voter pour un article ; nous avons donc cliqué dans le vide juste pour nous connecter.

Les gros problèmes concernant le frontend se sont plus focalisés sur JSF 2.0 (le pauvre...) avec quelques hacks autour de la classe WebConfiguration. Un problème s'est aussi posé concernant le state saving de JSF 2.0 côté serveur. Les scopes doivent être réduits à request et à view, le state doit être sérialisé dans le view scope et (enfin et non des moindre) RichFaces et ICEFaces ne peuvent pas être utilisés (whitelisted classes). Beaucoup de ralentisseurs donc mais qui n'ont pas empêché l'application d'être disponible et fonctionnelle à Devoxx.

Pour GWT, beaucoup de temps a aussi été investi pour brancher les services remotes sur Spring convenablement (avec P.G Taboada's AutoinjectingRemoteServiceServlet). Les problèmes majeurs rencontrés dans le développement de l'application GWT se situent au niveau de son protocole GWT-RPC et de l'impossibilité de sérialiser des types Text et Blob de BigTable. Gilead (anciennement Hibernate4GWT) aurait pu aider dans la gestion de ce mapping mais cela n'a pas fonctionné. La solution de contournement a donc été de créer des DTOs pour tous les spring beans ! De plus, ces DTOs, spécifiques à l'application ne sont pas compatible avec les tableaux SmartGWT. Il a donc fallu les copier dans les records SmartGWT... Tout fonctionne mais avec beaucoup de beans passe-plats, le tout n'étant pas très automatique.

Conclusion

Au final, l'application Spring MVC, couche service incluse, n'aura pris que 3 jours à être codée. Alors que pour JSF 2.0 et GWT 1.7, on est plutôt sur 2 semaines chacun et uniquement pour la partie frontend (couche service partagée). La rapidité d'écriture est donc clairement à l'avantage de Spring MVC (pour cette application). JSF 2.0 a été très retardé par ses incompatibilités avec GAE alors que GWT aura péché par sa difficulté d'intégration avec Spring, les problèmes liés aux échanges RPC et Gilead qui n'a pas fonctionné.

Que peut-on réellement en tirer ? Premièrement les 3 frameworks, même si ce fût dur, fonctionnement correctement sur GAE, si on fait abstraction des quelques Errors qui apparaissaient de temps à autre sur le grand écran. On pourra mettre ça sur le dos du wifi de Devoxx qui ne monte pas très bien en charge :) .

Parmi les liens utiles, on notera la recherche sur google de "Will it work on app engine" qui donne en premier résultat un site listant de manière assez complète les librairies et leur compatibilité sur GAE : http://groups.google.com/group/google-appengine-java/web/will-it-play-in-app-engine mais aussi le GAE Bar http://aralbalkan.com/1784.

Mots-clefs :,