Publié par

Il y a 10 ans -

Temps de lecture 7 minutes

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.

Publié par

Publié par Romain Maton

Après trois années passées chez Improve Technologies, Romain est aujourd'hui consultant Java/JEE chez Xebia. Mission après mission, il s’est forgé une solide expérience en développement Web et logiciel. Il dispose ainsi d'une très large compétence sur l'emsemble de l'ecosystème JEE, que ce soit sur les bonnes pratiques d'architecture, sur les frameworks de développement ou sur les interfaces client riches. Inconditionnel du pair programming, certifié Scrum Master, c'est un fervent disciple des méthodes Agiles. Romain est aussi un contributeur actif de la revue de presse Xebia. Il traite de nombreux sujets tels que RIA, API Java, frameworks ou bien encore Scala.

Commentaire

9 réponses pour " Devoxx – Jour 2 – Google App Engine "

  1. Publié par , Il y a 10 ans

    Marrant de lire qu’il a été question de ma librairie (Gilead) lors de Devoxx :)
    (même si c’est pour dire que cela n’a pas fonctionné…).

    Pour info, le support des types spécifiques DataNucleus (Text, Blob, …) a été rajouté depuis quelques semaines dans le trunk de l’application et sera disponible dans la prochaine release 1.3.
    (je ne sais pas si c’est ce qui a fait que cela n’a pas fonctionné : personne ne m’a remonté de problème particulier sur les forums du projet :-/)

  2. Publié par , Il y a 10 ans

    @Romain thanks for the fantastic writeup of our talk!

    @Bruno I’m sorry I didn’t leave any feedback in the Gilead forums. I should have. When I tested Gilead, Blob types worked but not appengine type Text. I’ll check the nightly builds and see if I can get it working.

  3. Publié par , Il y a 10 ans

    Je suis déçu de lire qu’il a été plus long de développer avec GWT qu’avec spring-mvc. J’ai l’impression que les développeurs qui se sont lancés là dedans n’ont pas pris le temps d’étudier GWT.

    http://code.google.com/intl/fr-FR/webtoolkit/doc/1.6/DevGuideCodingBasics.html#DevGuideJavaCompatibility

    Les Pojo doivent suivre quelques règles:
    – ils doivent être serializable
    – constructeur par defaut
    – getter / setter
    – ils doivent faire partie du runtime GWT (partie cliente)

    Si vous étendez les classes Spring ca ne m’étonne pas que cela ne marche pas. Ca n’est pas Gilead qui ne fonctionne pas, mais c’est l’architecture qui à un problème.

    Hibernate, avec ses annotations, n’est pas intrusif dans le code des Pojo. C’est pour ca que Gilead fonctionne bien dans ce cas.

    Si vous étendez des classes Spring sur vos Pojo, vos pojos ne sont plus de simple pojo, mais il y a du code intrusif qui n’est pas compilable pour le côté client de GWT. Et donc la serialization de la réponse Rpc ne fonctionne pas.

    Avec de simples Pojos, ça aurait fonctionné.

  4. Publié par , Il y a 10 ans

    @philippe Voncken: We didn’t extend Spring classes. The POJOs have pure JDO annotations.

    Here’s a SwagItem: http://code.google.com/p/swagswap/source/browse/trunk/src/main/java/com/swagswap/domain/SwagItem.java

    I’m extending a the Spring JdoDaoSupport in the DAO though.

    http://code.google.com/p/swagswap/source/browse/trunk/src/main/java/com/swagswap/dao/ItemDaoImpl.java

    The Gilead problem is with the appengine datatypes we used in the domain objects.

  5. Publié par , Il y a 10 ans

    @Sam

    1. Effectivement ton pojo n’étend pas de classe Spring, mais l’erreur sur laquel tu es tombé revient au même.

    Tu utilises en attribut de ton Pojo un objet Text qui vient de l’API appEngine. C’est normal que Text ne compile pas dans le côté client de GWT. Tu aurais dû utiliser un String avec une annotation pour dire que tu veux le persister de la manière que tu le souhaites.

    Par exemple @Lob -> javax.persistence.Lob

    2. Vous auriez gagné du temps en utilisant un dao générique. Réimplémenter un dao pour chaque Pojo est fastidieux

    #traduction pour Sam
    #in English
    1. The class Text come from appEngin API. It’s normal that don’t work in GWT client. you must used a String with @Lob annotation for obtain a Blob.

    2. You would have saved time with a generic DAO.

  6. Publié par , Il y a 10 ans

    Juste une précision : c’est la sérialisation GWT qui empêche l’envoi des entités du DataStore vers le coté client, et non Gilead ;)

    Gilead modifie au contraire cette serialisation pour que le transfert se passe sans heurts. Mais en effet, la première version de la librairie ne prenait en charge que la partie sérialisation, et non les types spécifiques (Text, Blob, etc…)

    Depuis, le support de ces derniers été ajoutée par émulation JS correspondante, et devrait, si tout va bien, simplifier la vie de Sam :)

  7. Publié par , Il y a 10 ans

    @philippe Voncken:
    I don’t think you can make a string attribute and have JDO save it as a BLOB in Appengine. Correct me if I’m wrong.

    Making an abstract DAO with CRUD operations wouldn’t have made it any simpler. Just more abstract. Harder to explain in my talk. But nice thought.

  8. Publié par , Il y a 10 ans

    Thanks Philippe that’s gonna help a lot!

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nous recrutons

Être un Xebian, c'est faire partie d'un groupe de passionnés ; C'est l'opportunité de travailler et de partager avec des pairs parmi les plus talentueux.