Il y a à peu près un an, Google ouvrait l'App Engine aux développeurs, il n'était alors possible de déployer que des applications développées en Python.
Pour rappel, Google App Engine est une offre de Cloud Computing permettant aux développeurs d’héberger leurs applications Web sur les serveurs de Google. Les applications ainsi hébergées bénéficient de ce fait de la même capacité de montée en charge que les services Google tels que Gmail ou Google Finance.
Google n’est pas la seule entreprise positionnée sur ce secteur, bien que pas tout à fait similaires, Amazon et Microsoft ont eux aussi leurs offres avec respectivement AWS et Windows Azure.
Un des atouts de Google App Engine c’est que gratuitement un développeur peut déployer une application qui soit accédées à raison de 5 millions de pages vues par mois. Ce qui est somme toute une offre d’hébergement intéressante. Au-delà de ces quotas, il est possible d’acheter des ressources supplémentaires.
Depuis quelques mois, nous pouvions voir dans la roadmap de ce projet que le support d’autres langages était un des objectifs de Google. Aujourd'hui, c’est chose faite, Google ouvre son service à une nouvelle communauté et contrairement à leur poisson d’avril, ce n’est pas Fortran mais bien Java qui est désormais supporté.
Cette nouvelle devrait donc être accueillie avec un vif enthousiasme lorsque l’on sait que le support de Java a été l’une des premières évolutions suggérées par les développeurs lors de la sortie de la première version de l’App Engine.
La version Java ne déroge pas au qualificatif de « Simple d’utilisation » qui caractérisait la version Python. En effet, il n’y a pas de différence majeure dans l’approche qu’ont ses deux dernières. Un atout supplémentaire de la version Java et qui a son importance, c’est le fait qu’elle s’accompagne d’un plugin Eclipse. Il est ainsi possible de créer une application et de la déployer en quelques clics.
De plus, l’intégration avec GWT (Google Web Toolkit) est enfantine et proposée par défaut par le plugin.
L’environnement de développement App Engine Java supporte les versions Java 5 et Java 6, sachant que sur les serveurs distants c’est la 6 qui est supportée. Les pré-requis au développement et au déploiement d’applications sur la plate-forme sont relativement faibles : avoir installé Java et le SDK de l’App Engine. L’installation du plugin Eclipse est bien entendu un plus non négligeable.
L’administration des applications se fait via la même interface que pour les applications Python. Il est ainsi possible de voir la répartition de la charge dans le temps, les requêtes HTTP les plus récurrentes, le taux d’utilisation ramené aux quotas. Il est également possible de consulter les logs. Enfin, une page permet d’accéder aux données stockées dans le Datastore.
Etudions de plus près l’architecture d’un projet et l’utilisation des APIs

Passons à la pratique : 

Les applications Google App Engine doivent être structurées en respectant l’arborescence WAR, ainsi, si vous créez un projet via le plugin Eclipse, vous obtiendrez une structuration semblable à celle-ci :

Cette arborescence de projet ne présente pas de spécificité particulière, on notera la présence d’un fichier web.xml permettant d’assurer le mapping entre les URLs et les classes des Servlets.
Lorsque vous déployez une application sur Google App Engine, une association s’opère entre les fichiers que vous transférez sur les serveurs de Google et les applications que vous êtes en mesure d’administrer. Cette association est possible grâce à un identifiant que vous vous devez de retranscrire dans le fichier appengine-web.xml. Ce fichier est l’équivalent du fichier app.yaml de la version Python de l’App Engine.
Les Servlets sont tout à fait communes et ne différent pas de celles que l’on peut développer dans une application traditionnelle. La Servlet d’un HelloWorld pourrait donc se présenter ainsi :

package com.sfeir.demo;

import java.io.IOException;
import javax.servlet.http.*;

public class DemoServlet extends HttpServlet {
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        resp.setContentType("text/plain");
        resp.getWriter().println("Hello, world");
    }
}


Maintenant que nous savons qu’il n’est pas difficile de créer un projet, intéressons nous aux APIs spécifiques de Google App Engine.

Utiliser les APIs :

Authentification

Ajouter un système d’authentification des utilisateurs se fait tout aussi facilement qu’avec la version Python :

package com.sfeir.demo;

import java.io.IOException;
import javax.servlet.http.*;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

public class DemoServlet extends HttpServlet {
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
              throws IOException {
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();

        if (user != null) {
            resp.setContentType("text/plain");
            resp.getWriter().println("Hello, " + user.getNickname());
        } else {
            resp.sendRedirect(userService.createLoginURL(req.getRequestURI()));
        }
    }
}


Ici, on utilise le UserService pour récupérer l’utilisateur actuellement connecté à l’application. S’il y a bel et bien un utilisateur authentifié, nous lui affichons un message de bienvenue et si ce n’est pas le cas, l’API nous permet de le rediriger vers une page de login. Lorsque vous travaillez en « local », le système d’authentification est émulé, il n’y a pas de vérification à proprement parler de l’existence des utilisateurs. Lorsque vous déployez votre application, le UserService se base sur les Google Accounts pour vérifier l’existence des utilisateurs.

Il est également possible de savoir si l’utilisateur actuellement authentifié est un administrateur de l’application et ainsi de lui donner accès ou non à certaines fonctionnalités.

Persistance


Attention, comme pour la version Python de Google App Engine, le stockage des données ne s’effectue pas dans une base de données relationnelle. Google dispose de son propre formalisme de stockage des données qui s’apparente à une Map multidimensionnelle partagée.
Le développeur dispose de trois solutions distinctes pour persister ses données, en effet, Google App Engine Java implémente JDO (Java Data Object), JPA (Java Persitance API) et met également à disposition une API de plus bas niveau (Datastore API).
Dans cette version de Google App Engine, Google pousse un Framework de persistance : DataNucleus. Sa configuration se fait très simplement (voir doc pour plus de détails)
Voici un exemple utilisant JDO, la définition des données à persister se fait par annotation.
Ci-dessous, l’objet Comment est défini comme pouvant être persisté, en le sauvant, les éléments annotés comme @Persistent feront parti de la sauvegarde.

package com.sfeir.demo;

import java.util.Date;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.users.User;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Comment {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;

    @Persistent
    private User author;

    @Persistent
    private String content;

    @Persistent
    private Date date;

    public Comment(User author, String content, Date date) {
        this.author = author;
        this.content = content;
        this.date = date;
    }

}

Il est ensuite très simple de manipuler cet objet au travers de l’API. Ainsi, pour persister une instance de cet objet, on peut utiliser le PersistenceManager de la manière suivante :

Comment comment = new Comment(user.getNickName(), content, new Date()) ;
PersistenceManagerFactory pmfInstance =
        JDOHelper.getPersistenceManagerFactory("transactions-optional");
      PersistenceManager pm = pmfInstance.get().getPersistenceManager();
        try {
            pm.makePersistent(comment);
        } finally {
            pm.close();
        }



Avec ce PersistenceManager, il est tout aussi simple de récupérer un objet pm.getObjectById(…) ou encore de le supprimer pm.deletePersistent(…).
Au même titre qu’il était possible d’interroger la base au travers du GQL dans la version Python, il est ici possible d’utiliser un langage de requête proche de SQL pour récupérer des données, il s’agit de JDOQL.
On pourrait récupérer la liste de nos commentaires ainsi :

PersistenceManagerFactory pmfInstance =
        JDOHelper.getPersistenceManagerFactory("transactions-optional");

PersistenceManager pm = pmfInstance.get().getPersistenceManager();

String query = "select from " + Comment.class.getName();
List<Comment> comments = (List<Comment>) pm.newQuery(query).execute() ;


Gestion d'un cache mémoire


Afin de ne pas surcharger le Datastore avec des requêtes récurrentes, il peut être intéressant de stocker un certain nombre d’informations dans un cache mémoire. Cela peut se faire très simplement au travers de l’utilisation de la Memcache API.

cache = CacheManager.getInstance().getCacheFactory().createCache(Collections.emptyMap());
cache.put(‘‘cachedInteger’’, 25) ;
Integer cachedValue = (Integer) cache.get(‘‘cachedInteger’’);



Dans l’exemple ci-dessus, après avoir récupéré l’instance du cache mémoire, on y insère un entier à la clef « cachedInteger » au travers d’un put. Un simple get avec la clef nous permet de récupérer la donnée que nous avions mise en cache.
Le cache est utilisé pour cet exemple de manière très simpliste mais on pourrait imaginer l’utiliser pour retourner des informations ayant plus de valeur, comme le contenu RSS de l’application ou encore une page fréquemment requêtée.
Cette API de cache propose d’autres fonctionnalités intéressantes comme la possibilité de définir une période de validité pendant laquelle les données peuvent être considérées comme « fraiches ». Différentes politiques de gestion sont également applicables, ainsi il est possible de n’ajouter la donnée que si celle-ci est déjà présente ou réciproquement.

Envoi de mail


L'envoi de mail fait partie des fonctionnalités intégrées à Google App Engine et relativement simples à mettre en place au sein d'un projet.
Dans cette version Java, l'API implémente l'interface JavaMail, pour des raisons de sécurité, seules les adresses d’un administrateur de l’application ou celle de l’utilisateur couramment authentifié peuvent être spécifiées comme adresses de l’émetteur.
       

Properties props = new Properties();
        Session session = Session.getDefaultInstance(props, null);

        String msgBody = "Contenu du mail";

        ...
        Message msg = new MimeMessage(session);
        msg.setFrom(new InternetAddress("admin@mondomaine.com"));
        msg.addRecipient(Message.RecipientType.TO,new InternetAddress("destinataire@sondomaine.com", "Destinataire"));
        msg.setSubject("Email envoyé par Google App Engine");
        msg.setText(msgBody);
        Transport.send(msg);


L’exemple ci-dessus montre l’envoi d’un mail basic, sachez qu’il est également possible d’ajouter des pièces jointes (voir types MIME autorisés) avec la contrainte toutefois que l’e-mail ne dépasse pas les 1mb.

Comme pour la version Python, il est également mis à la disposition des développeurs une API permettant d’interroger des hôtes distants (via l’API URL FETCH) et une autre permettant de manipuler des images.

Cette version de Google App Engine étant toute récente, il va être intéressant de suivre l’adhésion des développeurs de la communauté Java à ce service. D’une part, elle offre une grande facilité de développement et de ce fait un gain de temps dans l’élaboration d’applications, ce qui devrait en attirer plus d’un. D’autre part, tout comme pour la version Python un certain nombre de quotas et de restrictions sont à prendre en compte lors de l’utilisation de ce service, ce qui exclu certain types d’applications de cette offre d’hébergement.

Cette nouvelle version est également un beau coup de pousse donné à GWT, en effet le plugin Eclipse permet de créer en quelques clics une application GWT pour Google App Engine et devrait donc  amener davantage de développeurs à adopter ce Framework Web.

Google Guice sera peut être un autre des bénéficiaires de cette version Java, bien qu’il ne soit pas poussé outre mesure par Google pour être associé à Google App Engine, sa légèreté et sa simplicité d’utilisation devrait lui permettre de s’intégrer facilement aux applications déployées sur la plate-forme.

Quoi qu’il en soit c’est une nouveauté que nous nous devons de suivre.

Références :

Pour s'inscrire
L'annonce officielle
Le Coud Computing
Tout sur Google App Engine
DataNucleus
Découvrir GWT
En savoir plus sur GUICE
Amazon Web Services
Windows Azure