tp4 utilisation de google app engine en java
Transcription
tp4 utilisation de google app engine en java
TP4 UTILISATION DE GOOGLE APP ENGINE EN JAVA Table des matières TP4 Utilisation de Google APP Engine en Java ___________________________________ 1 TP4 Utilisation de Google APP Engine en Java ___________________________________ 2 Qu'est-ce que Google App Engine (document google) ___________________________________________ Mise en place des outils ___________________________________________________________________ Création d'un projet ______________________________________________________________________ Le Répertoire des projets __________________________________________________________________ Mise en place du projet ___________________________________________________________________ La classe Servlet ________________________________________________________________________ Le fichier web.xml ________________________________________________________________________ Le fichier appengine-web.xml _______________________________________________________________ Exécution du projet _______________________________________________________________________ Erreurs avec la configuration par défaut ______________________________________________________ 2 2 4 4 4 4 5 5 5 6 Utilisation du service Users ________________________________________________________ 7 Mise en œuvre du service Users __________________________________________________________ 7 Étapes suivantes... ______________________________________________________________________ 8 Utilisation des JSP ________________________________________________________________ 9 Bonjour, JSP ! __________________________________________________________________________ 9 Formulaire du livre d'or _________________________________________________________________ 10 Étapes suivantes... _____________________________________________________________________ 12 Utilisation du magasin de données avec JDO _________________________________________ 13 Configuration de la plate-forme d'accès DataNucleus ________________________________________ Amélioration des classes JDO ___________________________________________________________ Objets POJO et annotations JDO _________________________________________________________ PersistenceManagerFactory _____________________________________________________________ Création et enregistrement d'objets _______________________________________________________ Requêtes avec JDOQL __________________________________________________________________ Étapes suivantes... _____________________________________________________________________ 13 14 14 16 16 17 20 Utilisation des fichiers statiques ___________________________________________________ 21 Feuille de style simple __________________________________________________________________ 21 Étapes suivantes... _____________________________________________________________________ 21 Transfert de votre application ______________________________________________________ 22 Enregistrement de l'application __________________________________________________________ 22 Transfert de l'application ________________________________________________________________ 22 Architectures réparties et Cloud Computing TP4 UTILISATION DE GOOGLE APP ENGINE EN JAVA QU'EST-CE QUE GOOGLE APP ENGINE (DOCUMENT GOOGLE) Google App Engine vous permet d'exécuter vos applications Web sur l'infrastructure Google. Faciles à développer et à gérer, les applications App Engine, grâce à leur caractère évolutif, s'adaptent à vos besoins en termes de trafic et de stockage des données. App Engine vous dispense du recours à tout serveur : il vous suffit de transférer votre application et le tour est joué ! Vos utilisateurs peuvent s'en servir sans plus attendre. Vous pouvez diffuser votre application à partir de votre propre nom de domaine (tel que http://www.example.com/) en utilisant Google Apps. Vous pouvez également choisir d'utiliser un nom gratuit sur le domaine appspot.com. Vous pouvez partager votre application avec le reste du monde, ou en limiter l'accès aux membres de votre entreprise. Google App Engine prend en charge les applications écrites en plusieurs langages de programmation. Avec l'environnement d'exécution Java d'App Engine, vous pouvez développer votre application en utilisant les technologies Java standard, notamment la machine virtuelle Java, les servlets Java et le langage de programmation Java (ou tout autre langage faisant appel à un interpréteur ou à un compilateur compatibles avec la machine virtuelle Java, tel que JavaScript ou Ruby). App Engine est également doté d'un environnement d'exécution Python dédié, qui inclut un interpréteur Python rapide ainsi que la bibliothèque standard de Python. Les environnements d'exécution Java et Python sont conçus de manière à garantir l'exécution rapide et sécurisée de votre application, sans interférence des autres applications du système. Avec App Engine, vous payez uniquement ce que vous consommez. Il n'existe ni frais initiaux, ni frais récurrents. Les ressources utilisées par votre application, telles que l'espace de stockage et la bande passante, sont mesurées en gigaoctets et facturées à des tarifs compétitifs. Vous avez le contrôle sur les quantités maximales de ressources consommées, afin de ne jamais dépasser votre budget. Vous n'avez rien à payer pour utiliser App Engine. Toutes les applications peuvent utiliser jusqu'à 500 Mo d'espace de stockage, et assez de temps processeur et de bande passante pour une diffusion efficace, équivalente à une consultation mensuelle de 5 millions de pages, et ce totalement gratuitement. Lorsque vous activez la fonction de facturation pour votre application, les niveaux de gratuité des ressources sont élevés, et vous payez uniquement ce que vous consommez au-delà de ces limites. MISE EN PLACE DES OUTILS On utilisera le système exploitation Windows 7 virtualisé pour le développement des applications. Les pré-requis nécessaires dans la machine de développement sont les suivant : Présence du JDK java (téléchargeable l’adresse suivante : http://www.oracle.com/technetwork/java/javase/downloads/index.html . Choisir un JDK SE 6 Update 29 (ne pas prendre le JDK 7). Installer le JDK avec les options par défaut. L’application Eclipse Indigo SR1 (téléchargeable l’adresse suivante : http://www.eclipse.org/downloads/ Prendre la version 32 bits pour Java EE developers. Décompacter Eclipse à la racine du disque dur virtuel (c ou d). Vous pouvez franciser Eclipse en installant le greffon (à partir du menu aide/Install/ New Software) : http://download.eclipse.org/technology/babel/update-site/R0.9.0/indigo. Lors du lancement d’eclipse proposer le répertoire de travail GoogleAppEngine Dans Eclipse installer le plugin APP ENGINE de Google : voir http://code.google.com/intl/fr-FR/eclipse/docs/install-eclipse-3.7.html Ne pas installer les outils pour Android (le plugin d’Android n’est pas installé) Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 2/23 Architectures réparties et Cloud Computing Documentation App Engine : http://code.google.com/intl/fr-FR/appengine/ Documentation App Engine pour java : http://code.google.com/intl/fr-FR/appengine/docs/java Pour la partie du TP exécutée en local utiliser le navigateur Microsoft IE. Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 3/23 Architectures réparties et Cloud Computing CREATION D'UN PROJET Les applications Java App Engine utilisent le standard Java Servlet pour interagir avec l'environnement du serveur web. Une application comporte des classes compilées, des fichiers JAR, des fichiers statiques et des fichiers de configuration. Ces fichiers sont disposés dans une structure de répertoire en utilisant la norme WAR norme pour les applications web Java. On peut utiliser n'importe quel processus de développement pour développer des servlets web et de produire un répertoire WAR. L’environnement de développement Eclipse avec le plugin Google App Engine facilite beaucoup la création de ce type d’application. LE REPERTOIRE DES PROJETS Pour cet exemple, nous allons utiliser un seul répertoire nommé Guestbook (Livre d'or) pour tous les fichiers du projet. Un sous-répertoire nommé src contient le code source Java, et un sous-répertoire nommé war contenant l'application complète au format WAR. Le processus de construction compile les fichiers source Java et met les classes compilées dans l'emplacement approprié dans war. Le répertoire du projet complet ressemble à ceci: Guestbook/ src/ ...Java source code... META-INF/ ...other configuration... war/ ...JSPs, images, data files... WEB-INF/ ...app configuration... lib/ ...JARs for libraries... classes/ ...compiled classes... MISE EN PLACE DU PROJET Après avoir lancé Windows 7 depuis l’hyperviseur, lancer Eclipse à l’aide du raccourci situé dans C:\Users\user\Documents\AppEngine. Créer un nouveau projet en cliquant sur le New Web Application (bouton dans la barre d'outils: Donner au projet le nom Guestbook et dans un package guestbook. Décochez la case "Using Google Web Toolkit" et assurez-vous que "User Google App Engine" est cochée. LA CLASSE SERVLET Java App Engine utilise l'API Java Servlet pour interagir avec le serveur web. Une servlet HTTP est une classe d'application qui peut traiter et répondre à des requêtes Web. Cette classe doit hériter soit de la classe javax.servlet.GenericServlet soit de la classe javax.servlet.http.HttpServlet. Notre projet commence avec une classe servlet simple qui affiche un message. Dans le répertoire src du projet, le plugin a crée un fichier nommé GuestbookServlet.java de contenu suivant : package guestbook; import java.io.IOException; import javax.servlet.http.*; public class GuestbookServlet extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { resp.setContentType("text/plain"); resp.getWriter().println("Hello, world"); } } Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 4/23 Architectures réparties et Cloud Computing LE FICHIER WEB.XML Lorsque le serveur Web reçoit une requête, il détermine la classe servlet à appeler en utilisant un fichier de configuration appelé «descripteur de déploiement d'application web ». Ce fichier est nommé web.xml réside dans le war/WEB-INF/ . WEB-INF / et web.xml font partie de la spécification des servlets. Le fichier déclare une servlet nommée Guestbook, et lui associe un chemin d’url /Guestbook. web.xml donne le chemin à l’intérieur de l’application WAR d’un fichier htlm (ici index.html) qui sera utilisé par le serveur chaque fois que l'utilisateur récupère une URL qui n'est pas déjà associé à une servlet. LE FICHIER APPENGINE-WEB.XML App Engine a besoin d'un fichier de configuration supplémentaires pour trouver la façon de déployer et d'exécuter l'application. Ce fichier est nommé appengine-web.xml réside dans WEB-INF/ à côté de web.xml. Il inclut un identificateur (l'ID de application), le numéro de version de votre application, et des listes de fichiers qui doivent être traités comme des fichiers statiques (tels que des images et des feuilles de style CSS) et les fichiers de ressources (telles que les JSP et autres données d'application). Eclipse crée une zone vide, à vous de la remplir plus tard, <?xml version="1.0" encoding="utf-8"?> <appengine-web-app xmlns="http://appengine.google.com/ns/1.0"> <application></application> <version>1</version> </appengine-web-app> appengine-web.xml est spécifique à App Engine et ne fait pas partie de la norme servlet. Les schémas XML décrivant le format de ce fichier est dans le répertoire du sdk App Engine appengine-java-sdk/docs. Voir Configuration d'une appli pour plus d'informations sur ce fichier. EXECUTION DU PROJET Le SDK App Engine inclut un serveur Web de développement utilisé pour tester votre application. Le serveur simule l'environnement App Engine et les services correspondants, y compris les restrictions du bac à sable (sandbox), le stockage des données, et les services. Pour démarrer le serveur de développement dans le débogueur Eclipse sélectionner le projet Guestbook, puis clic droit et choisir Déboguer en tant que > Web Application Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 5/23 Architectures réparties et Cloud Computing détails sur la création de la Démarrez le serveur. Pour lancer : le fichier index.htlm, entrer l'url suivante dans votre navigateur : http://localhost:8888/. directement la servlet, entrer l’url dans votre navigateur : http://localhost:8888/guestbook . ERREURS AVEC LA CONFIGURATION PAR DEFAUT Dans la partie usings jsp, les jsp sont génèrent du code java à l’aide du compilateur java javac. Ce compilateur n’est pas dans le JRE, mais dans le JDK. Eclipse génère une erreur car il ne trouve pas le compilateur. Pour corriger cette erreur, aller dans menu Fenêtre préférences et ajouter un chemin vers le JDK (Ajouter -> VM standard -> Répertoire -> programmes -> java -> jdk_xy Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 6/23 Architectures réparties et Cloud Computing Utilisation du service Users Google App Engine fournit de nombreux services très utiles basés sur l'infrastructure Google et accessibles aux applications utilisant les bibliothèques du kit de développement de logiciels (SDK). Parmi eux, le service Users permet d'intégrer les comptes d'utilisateurs Google à votre application. Avec le service Users, les internautes peuvent se connecter à votre application à l'aide d'un compte Google existant. Nous allons maintenant faire appel au service Users pour personnaliser le message de bienvenue de cette application. Mise en œuvre du service Users Modifiez le fichier src/guestbook/GuestbookServlet.java, comme suit : package guestbook; import import import import import java.io.IOException; javax.servlet.http.*; com.google.appengine.api.users.User; com.google.appengine.api.users.UserService; com.google.appengine.api.users.UserServiceFactory; public class GuestbookServlet 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())); } } } Si vous utilisez Eclipse et que votre serveur de développement s'exécute dans le débogueur, Eclipse compile automatiquement le nouveau code lorsque vous enregistrez vos modifications dans ce fichier, puis il tente d'insérer le nouveau code dans le serveur en cours d'exécution. Toutes les modifications apportées aux classes, aux pages JSP, aux fichiers statiques et au fichier appengine-web.xml sont immédiatement prises en compte sans avoir besoin de redémarrer le serveur en cours d'exécution. Si vous modifiez le fichier web.xml ou tout autre fichier de configuration, vous devez arrêter, puis redémarrer le serveur pour que les modifications prennent effet. Recompilez votre projet et redémarrez le serveur, si nécessaire. Testez l'application en tapant l'URL de servlet suivante dans votre navigateur : http://localhost:8888/guestbook Au lieu d'afficher le message, le serveur vous invite à saisir une adresse e-mail. Entrez une adresse e-mail (par exemple, [email protected]), puis cliquez sur "Log In" (Connexion). L'application affiche un message, avec l'adresse e-mail que vous avez saisie. Le nouveau code de la classe GuestbookServlet utilise l'API Users pour vérifier que l'utilisateur est connecté à un compte Google. Si ce n'est pas le cas, l'utilisateur est redirigé vers la page de connexion de Google Accounts. userService.createLoginURL(...) renvoie l'URL de l'écran de connexion. Le système de Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 7/23 Architectures réparties et Cloud Computing connexion redirige l'utilisateur vers l'application à l'aide de l'URL transmise à createLoginURL(...), qui correspond dans notre cas à l'URL de la page en cours. Le serveur de développement sait comment simuler le système de connexion de Google Accounts. Lorsque vous exécutez l'application sur votre machine locale, vous êtes redirigé vers la page dans laquelle vous avez entré l'adresse e-mail pour simuler une connexion à un compte. Lorsque vous exécutez l'application sur App Engine, vous êtes redirigé vers l'écran de Google Accounts. Vous êtes maintenant connecté à votre application de test. Si vous rechargez la page, le message s'affiche de nouveau. Pour permettre à l'utilisateur de se déconnecter, vous devez fournir un lien vers l'écran de déconnexion, généré par la méthode createLogoutURL(). Sachez que ce lien déconnectera l'utilisateur de l'ensemble des services Google. Étapes suivantes... Maintenant que vous savez comment identifier l'utilisateur, vous pouvez l'inviter à poster des messages dans le livre d'or. Pour ce faire, nous allons développer une interface utilisateur à l'aide de pages JSP. Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 8/23 Architectures réparties et Cloud Computing Utilisation des JSP Bien qu'il soit possible de générer une sortie HTML pour l'interface utilisateur directement à partir du code de servlet Java, cela serait trop difficile et compliqué. À la place, nous vous conseillons d'utiliser un modèle, avec l'interface utilisateur conçue et implémentée dans des fichiers séparés avec une logique et des emplacements réservés pour insérer les données fournies par l'application. Un grand nombre de modèles disponibles sous Java sont compatibles avec App Engine. Au cours de ce didacticiel, nous utiliserons les pages JavaServer (JSP) pour implémenter l'interface utilisateur du livre d'or. La technologie JSP fait partie intégrante de la norme Servlet. App Engine compile automatiquement les fichiers JSP dans le fichier d'archives WAR de l'application, et les mappe sur les chemins d'URL. Bonjour, JSP ! Notre application de livre d'or écrit les chaînes dans un flux de sortie standard, mais elles pourraient également être écrites en tant que page JSP. Commençons par adapter la dernière version de l'exemple à JSP. Dans le répertoire war/, créez un fichier appelé guestbook.jsp avec les éléments suivants : <%@ <%@ <%@ <%@ page page page page contentType="text/html;charset=UTF-8" language="java" %> import="com.google.appengine.api.users.User" %> import="com.google.appengine.api.users.UserService" %> import="com.google.appengine.api.users.UserServiceFactory" %> <html> <body> <% UserService userService = UserServiceFactory.getUserService(); User user = userService.getCurrentUser(); if (user != null) { %> <p>Hello, <%= user.getNickname() %>! (You can <a href="<%= userService.createLogoutURL(request.getRequestURI()) %>">sign out</a>.)</p> <% } else { %> <p>Hello! <a href="<%= userService.createLoginURL(request.getRequestURI()) %>">Sign in</a> to include your name with greetings you post.</p> <% } %> </body> </html> Par défaut, tous les fichiers situés dans un fichier d'archives war/ ou un sous-répertoire (autre que WEB-INF/) dont le nom se termine par .jsp sont automatiquement mappés sur un chemin d'URL. Le chemin d'URL est le chemin d'accès au fichier .jsp, incluant le nom de fichier . Cette page JSP sera mappée automatiquement sur l'URL /guestbook.jsp. Dans le cadre de notre livre d'or, nous voulons que cette page soit la page d'accueil qui s'affiche lorsqu'un utilisateur accède à l'URL /. La méthode la plus simple consiste à déclarer dans web.xml que guestbook.jsp est le servlet de "bienvenue" associé à ce chemin. Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 9/23 Architectures réparties et Cloud Computing Modifiez le fichier war/WEB-INF/web.xml et remplacez l'élément <welcome-file> actuel dans la liste <welcome-file-list>. Assurez-vous de supprimer index.html de la liste, compte tenu que les fichiers statiques sont prioritaires sur les servlets et les pages JSP. <welcome-file-list> <welcome-file>guestbook.jsp</welcome-file> </welcome-file-list> Conseil : Si vous utilisez Eclipse, il se peut que l'éditeur ouvre ce fichier en mode conception. Pour modifier ce fichier au format XML, sélectionnez l'onglet "Source" situé dans la partie inférieure du cadre. Arrêtez, puis redémarrez le serveur de développement. Accédez à l'URL suivante : http://localhost:8888/ L'application affiche le contenu du fichier guestbook.jsp, notamment le pseudonyme de l'utilisateur si ce dernier est connecté. Lorsque vous chargez une page JSP pour la première fois, le serveur de développement convertit la page JSP en code source Java, puis compile la source en bytecode Java. La source Java et la classe compilée sont enregistrées dans un répertoire temporaire. Le serveur de développement regénère et compile automatiquement les pages JSP si les fichiers JSP d'origine ont été modifiés. Lorsque vous transférez votre application vers App Engine, le SDK compile toutes les pages JSP en bytecode, et ne transfère que le bytecode. Lorsque l'application s'exécute sur App Engine, elle utilise les classes JSP compilées. Formulaire du livre d'or Notre livre d'or nécessite maintenant un formulaire Web pour que les utilisateurs puissent poster un nouveau message, ainsi qu'une méthode de traitement de ce formulaire. Le contenu HTML du formulaire sera transmis à la page JSP. La destination du formulaire sera une nouvelle URL, /sign, traitée par une nouvelle classe de servlet, SignGuestbookServlet. SignGuestbookServlet traitera le formulaire, puis redirigera le navigateur de l'utilisateur vers /guestbook.jsp. Pour le moment, le nouveau servlet consignera simplement le message posté dans le fichier journal. Modifiez le fichier guestbook.jsp et insérez les lignes suivantes juste avant la balise </body> fermante : ... <form action="/sign" method="post"> <div><textarea name="content" rows="3" cols="60"></textarea></div> <div><input type="submit" value="Post Greeting" /></div> </form> </body> </html> Créez une classe nommée SignGuestbookServlet dans le package guestbook. (Les utilisateurs qui n'utilisent pas Eclipse doivent créer le fichier SignGuestbookServlet.java dans le répertoire src/guestbook/.) Insérez les éléments suivants dans le fichier source : Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 10/23 Architectures réparties et Cloud Computing package guestbook; import import import import import import java.io.IOException; java.util.logging.Logger; javax.servlet.http.*; com.google.appengine.api.users.User; com.google.appengine.api.users.UserService; com.google.appengine.api.users.UserServiceFactory; public class SignGuestbookServlet extends HttpServlet { private static final Logger log = Logger.getLogger(SignGuestbookServlet.class.getName()); public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { UserService userService = UserServiceFactory.getUserService(); User user = userService.getCurrentUser(); String content = req.getParameter("content"); if (content == null) { content = "(No greeting)"; } if (user != null) { log.info("Greeting posted by user " + user.getNickname() + ": " + content); } else { log.info("Greeting posted anonymously: " + content); } resp.sendRedirect("/guestbook.jsp"); } } Modifiez le fichier war/WEB-INF/web.xml et ajoutez les lignes suivantes pour déclarer le servlet SignGuestbookServlet, puis mappez-le sur l'URL /sign : <web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5"> ... <servlet> <servlet-name>sign</servlet-name> <servlet-class>guestbook.SignGuestbookServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>sign</servlet-name> <url-pattern>/sign</url-pattern> </servlet-mapping> ... </web-app> Ce nouveau servlet se sert de la classe java.util.logging.Logger pour écrire les messages dans le journal. Il vous est possible de contrôler le comportement de cette classe par l'intermédiaire d'un fichier logging.properties ainsi que d'une propriété système définie dans le fichier appengine-web.xml de l'application. Si vous utilisez Eclipse, votre application a été créée à l'aide de la version par défaut du fichier dans src/ et de la propriété système appropriée. Si vous n'utilisez pas Eclipse, vous devez configurer manuellement le fichier Logger. Copiez le fichier exemple du SDK appengine-java-sdk/config/user/logging.properties et collez-le dans le répertoire war/WEBINF/ de votre application. Modifiez ensuite le fichier war/WEB-INF/appengine-web.xml de l'application, comme suit : Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 11/23 Architectures réparties et Cloud Computing <appengine-web-app xmlns="http://appengine.google.com/ns/1.0"> ... <system-properties> <property name="java.util.logging.config.file" value="WEBINF/logging.properties"/> </system-properties> </appengine-web-app> Le servlet consigne les messages à l'aide du niveau de journalisation INFO (via log.info()). Le niveau par défaut est WARNING, qui supprime les messages INFO de la sortie. Pour modifier le niveau de journalisation de l'ensemble des classes du package guestbook, modifiez le fichier logging.properties et ajoutez une entrée guestbook.level, comme suit : .level = WARNING guestbook.level = INFO ... Conseil : Lorsque l'application consigne les messages à l'aide de l'API java.util.logging.Logger au cours de son exécution sur App Engine, App Engine enregistre les messages, qui sont alors accessibles dans laConsole d'administration et peuvent être téléchargés via l'outilAppCfg. La console d'administration permet de faire une recherche sur les messages en fonction de leur niveau de journalisation. Recompilez et redémarrez, puis testez l'adresse http://localhost:8888/. Le formulaire s'affiche. Entrez du texte et envoyez le formulaire. Le navigateur envoie le formulaire à l'application, puis le redirige vers le formulaire vide. Les données de bienvenue que vous avez saisies sont consignées dans la console par le serveur. Étapes suivantes... Nous avons créé une interface qui permet aux utilisateurs d'entrer des messages de bienvenue. Nous devons maintenant trouver un moyen de nous souvenir des messages postés par les utilisateurs et les afficher aux autres visiteurs. Pour ce faire, nous allons utiliser le magasin de données App Engine. Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 12/23 Architectures réparties et Cloud Computing Utilisation du magasin de données avec JDO Stocker des données dans une application Web évolutive peut s'avérer délicat. Un même utilisateur peut interagir avec des dizaines de serveurs Web à un instant t, et sa requête suivante peut être envoyée à un serveur Web différent de celui qui a traité la précédente. Les serveurs Web doivent manipuler des données réparties, elles aussi, sur des dizaines de machines qui sont parfois éparpillées aux quatre coins de la planète. Grâce à Google App Engine, vous n'avez pas à vous soucier de tout cela. L'infrastructure d'App Engine prend en charge la répartition et la réplication des données, ainsi que l'équilibrage des charges derrière une simple API. Elle offre en outre un moteur de requêtes puissant et permet aussi les transactions. Le magasin de données App Engine fait partie des nombreux services fournis par App Engine avec deux API : une API standard et une API de bas niveau. Lorsque vous utilisez les API standard, il est plus facile de porter votre application sur d'autres environnements d'hébergement et d'autres technologies de base de données, le cas échéant. Les API standard "dissocient" votre application des services App Engine. En outre, les services App Engine fournissent des API de bas niveau qui présentent directement les capacités de service. Les API de bas niveau permettent d'implémenter de nouvelles interfaces d'adaptateur ou d'utiliser les API directement dans votre application. App Engine prend en charge deux normes API différentes pour le magasin de données : JDO (Java Data Objects) et JPA (Java Persistence API). Ces interfaces sont fournies par la plate-forme d'accès DataNucleus, une implémentation Open Source de plusieurs normes de persistance Java, avec un adaptateur pour le magasin de données App Engine. Pour notre livre d'or, nous utiliserons l'interface JDO afin d'extraire et de poster les messages laissés par les utilisateurs. Configuration de la plate-forme d'accès DataNucleus La plate-forme d'accès requiert un fichier de configuration qui lui indique d'utiliser le magasin de données App Engine comme service principal pour l'implémentation JDO. Dans le fichier d'archives WAR final, ce fichier s'appelle jdoconfig.xml et se trouve dans le répertoire war/WEB-INF/classes/META-INF/. Si vous utilisez Eclipse, ce fichier a été créé pour vous sous la forme src/META-INF/jdoconfig.xml. Il est automatiquement copié dans war/WEB-INF/classes/META-INF/ lors de la génération du projet. Si vous n'utilisez pas Eclipse, vous pouvez directement créer le répertoire war/WEB-INF/classes/META-INF/, ou laisser le processus de génération s'en charger, puis copier le fichier de configuration à un autre emplacement. Le script de génération Ant décrit à la section Utilisation d'Apache Ant copie ce fichier à partir de src/META-INF/. Le fichier jdoconfig.xml doit comporter les éléments suivants : Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 13/23 Architectures réparties et Cloud Computing <?xml version="1.0" encoding="utf-8"?> <jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig"> <persistence-manager-factory name="transactions-optional"> <property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/> <property name="javax.jdo.option.ConnectionURL" value="appengine"/> <property name="javax.jdo.option.NontransactionalRead" value="true"/> <property name="javax.jdo.option.NontransactionalWrite" value="true"/> <property name="javax.jdo.option.RetainValues" value="true"/> <property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/> </persistence-manager-factory> </jdoconfig> Amélioration des classes JDO Lors de la création de vos classes JDO, vous utilisez les annotations Java pour décrire la manière dont les instances doivent être créées dans le magasin de données, ainsi que la manière dont elles doivent être recréées lorsqu'elles sont extraites du magasin de données. La plate-forme d'accès connecte vos classes de données à l'implémentation par le biais d'une étape de traitement de post-compilation, que DataNucleus appelle "amélioration" des classes. Si vous utilisez Eclipse et le plug-in Google, ce dernier intègre automatiquement l'étape d'amélioration des classes JDO à son processus de génération. Si vous utilisez le script de génération Ant décrit dans la section Utilisation d'Apache Ant, il inclut l'étape d'amélioration requise. Pour plus d'informations sur l'amélioration des classes JDO, consultez la section Utilisation de JDO. Objets POJO et annotations JDO JDO vous permet de stocker les objets Java (parfois appelés POJO) dans un magasin de données comportant un adaptateur compatible JDO, par exemple une plate-forme d'accès DataNucleus. Le SDK App Engine inclut un plug-in de plate-forme d'accès pour le magasin de données App Engine. Autrement dit, vous pouvez stocker les instances des classes que vous avez définies dans le magasin de données App Engine, puis les extraire en tant qu'objets à l'aide de l'API JDO. Vous indiquez à JDO comment stocker et reconstruire les instances de votre classe par le biais des annotations Java. Nous allons maintenant créer une classe Greeting permettant de représenter les messages individuels postés sur le livre d'or. Créez une classe nommée Greeting dans le package guestbook. (Les utilisateurs qui n'utilisent pas Eclipse doivent créer le fichier Greeting.java dans le répertoire src/guestbook/.) Insérez les éléments suivants dans le fichier source : Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 14/23 Architectures réparties et Cloud Computing package guestbook; import com.google.appengine.api.datastore.Key; import com.google.appengine.api.users.User; import import import import import java.util.Date; javax.jdo.annotations.IdGeneratorStrategy; javax.jdo.annotations.PersistenceCapable; javax.jdo.annotations.Persistent; javax.jdo.annotations.PrimaryKey; @PersistenceCapable public class Greeting { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key key; @Persistent private User author; @Persistent private String content; @Persistent private Date date; public Greeting(User author, String content, Date date) { this.author = author; this.content = content; this.date = date; } public Key getKey() { return key; } public User getAuthor() { return author; } public String getContent() { return content; } public Date getDate() { return date; } public void setAuthor(User author) { this.author = author; } public void setContent(String content) { this.content = content; } public void setDate(Date date) { this.date = date; } } Cette classe simple définit 3 propriétés pour un message de bienvenue : author, content et date. Ces trois champs privés sont annotés avec @Persistent pour indiquer à DataNucleus de les stocker en tant que propriétés d'objets dans le magasin de données App Engine. Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 15/23 Architectures réparties et Cloud Computing Cette classe définit les fonctions Getters et Setters des propriétés, qui sont utilisées uniquement par l'application. La méthode la plus simple afin de garantir que l'implémentation JDO reconnaît les mises à jour consiste à utiliser la fonction Setters. Le fait de modifier directement les champs permet de contourner la fonctionnalité JDO qui enregistre automatiquement les champs mis à jour, à moins que apportiez d'autres modifications au code en vue d'activer cette fonction. La classe définit également un champ appelé key, qui représente un élément Key annoté à la fois en tant que @Persistent et @PrimaryKey. Le magasin de données App Engine possède une notion de clé d'entité et peut représenter la clé de différentes manières sur l'objet. La classe Key représente tous les aspects des clés du magasin de données App Engine, notamment un identifiant numérique configuré automatiquement sur une valeur unique lors de l'enregistrement de l'objet. PersistenceManagerFactory Chaque requête utilisant le magasin de données crée une instance de la classe PersistenceManager. Cette opération s'effectue via une instance de la classe PersistenceManagerFactory. L'initialisation de l'instance PersistenceManagerFactory peut prendre du temps. Heureusement, vous n'avez besoin que d'une seule instance pour votre application, et celle-ci peut être stockée dans une variable statique disponible pour plusieurs requêtes et plusieurs classes. Pour ce faire, un moyen simple consiste à créer une classe wrapper singleton pour l'instance statique. Créez une classe appelée PMF dans le package guestbook (fichier nommé PMF.java dans le répertoire src/guestbook/), et saisissez le contenu suivant : package guestbook; import javax.jdo.JDOHelper; import javax.jdo.PersistenceManagerFactory; public final class PMF { private static final PersistenceManagerFactory pmfInstance = JDOHelper.getPersistenceManagerFactory("transactions-optional"); private PMF() {} public static PersistenceManagerFactory get() { return pmfInstance; } } Création et enregistrement d'objets Grâce à DataNucleus et à la classe Greeting, la logique de traitement des formulaires peut maintenant stocker de nouveaux messages de bienvenue dans le magasin de données. Modifiez le fichier src/guestbook/SignGuestbookServlet.java comme suit : Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 16/23 Architectures réparties et Cloud Computing package guestbook; import import import import import import import import java.io.IOException; java.util.Date; java.util.logging.Logger; javax.jdo.PersistenceManager; javax.servlet.http.*; com.google.appengine.api.users.User; com.google.appengine.api.users.UserService; com.google.appengine.api.users.UserServiceFactory; import guestbook.Greeting; import guestbook.PMF; public class SignGuestbookServlet extends HttpServlet { private static final Logger log = Logger.getLogger(SignGuestbookServlet.class.getName()); public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { UserService userService = UserServiceFactory.getUserService(); User user = userService.getCurrentUser(); String content = req.getParameter("content"); Date date = new Date(); Greeting greeting = new Greeting(user, content, date); PersistenceManager pm = PMF.get().getPersistenceManager(); try { pm.makePersistent(greeting); } finally { pm.close(); } resp.sendRedirect("/guestbook.jsp"); } } Ce code crée une nouvelle instance Greeting en appelant le constructeur. Pour enregistrer l'instance dans le magasin de données, il crée un élémentPersistenceManager à l'aide de PersistenceManagerFactory, puis transmet l'instance à la méthode makePersistent() de PersistenceManager. Les améliorations apportées aux annotations et au bytecode proviennent de là. Lorsque la méthode makePersistent() est renvoyée, le nouvel objet est stocké dans le magasin de données. Requêtes avec JDOQL JDOQL est le langage d'interrogation orienté objet persistant spécifié par la norme JDO. Vous pouvez l'utiliser pour interroger des entités dans le magasin de données App Engine et extraire les résultats en tant qu'objets JDO. Dans cet exemple, nous écrirons simplement le code de la requête directement dans guestbook.jsp. Dans le cadre d'une application plus importante, vous souhaiterez peut-être déléguer la logique d'interrogation à une autre classe. Modifiez le fichier war/guestbook.jsp et ajoutez les lignes suivantes : Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 17/23 Architectures réparties et Cloud Computing <%@ <%@ <%@ <%@ <%@ <%@ <%@ <%@ page page page page page page page page contentType="text/html;charset=UTF-8" language="java" %> import="java.util.List" %> import="javax.jdo.PersistenceManager" %> import="com.google.appengine.api.users.User" %> import="com.google.appengine.api.users.UserService" %> import="com.google.appengine.api.users.UserServiceFactory" %> import="guestbook.Greeting" %> import="guestbook.PMF" %> <html> <body> <% UserService userService = UserServiceFactory.getUserService(); User user = userService.getCurrentUser(); if (user != null) { %> <p>Hello, <%= user.getNickname() %>! (You can <a href="<%= userService.createLogoutURL(request.getRequestURI()) %>">sign out</a>.)</p> <% } else { %> <p>Hello! <a href="<%= userService.createLoginURL(request.getRequestURI()) %>">Sign in</a> to include your name with greetings you post.</p> <% } %> <% PersistenceManager pm = PMF.get().getPersistenceManager(); String query = "select from " + Greeting.class.getName(); List<Greeting> greetings = (List<Greeting>) pm.newQuery(query).execute(); if (greetings.isEmpty()) { %> <p>The guestbook has no messages.</p> <% } else { for (Greeting g : greetings) { if (g.getAuthor() == null) { %> <p>An anonymous person wrote:</p> <% } else { %> <p><b><%= g.getAuthor().getNickname() %></b> wrote:</p> <% } %> <blockquote><%= g.getContent() %></blockquote> <% } } pm.close(); %> <form action="/sign" method="post"> <div><textarea name="content" rows="3" cols="60"></textarea></div> <div><input type="submit" value="Post Greeting" /></div> </form> </body> </html> Pour préparer une requête, vous devez appeler la méthode newQuery() d'une instance PersistenceManager avec le texte de la requête en tant que chaîne. La méthode renvoie un objet de requête. La méthode execute() Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 18/23 Architectures réparties et Cloud Computing d'interrogation des objets effectue la demande, puis renvoie une liste List<> de résultats d'objets appropriés. La chaîne d'interrogation doit comporter le nom complet de la classe à interroger, y compris le nom du package. Générez de nouveau le projet, puis redémarrez le serveur. Accédez à http://localhost:8888/. Saisissez un message de bienvenue et soumettez-le. Il apparaît en haut du formulaire. Saisissez un autre message de bienvenue et soumettez-le. Les deux messages apparaissent. Déconnectez-vous, puis reconnectez-vous puis à l'aide des liens, et essayez de soumettre les messages lorsque vous êtes connecté et lorsque vous êtres déconnecté. Conseil : Dans une application réelle, il peut être judicieux de procéder au remplacement des caractères HTML lors de l'affichage du contenu utilisateur, à savoir les messages de bienvenue dans notre exemple. Pour ce faire, vous pouvez utiliser la bibliothèque JSTL (JavaServer Pages Standard Tag Library) qui inclut des routines appropriées. JSTL (et les autres JAR d'exécution compatibles JSP) étant fourni avec App Engine, il est inutile de les ajouter à votre application. Recherchez la fonction escapeXml dans la bibliothèque de balises http://java.sun.com/jsp/jstl/functions. Pour plus d'informations, consultez le Didacticiel Sun J2EE 1.4. Présentation de JDOQL Actuellement, notre livre d'or affiche l'ensemble des messages postés sur le système. En outre, il les affiche en fonction de leur date de création. Lorsque le livre d'or compte un grand nombre de messages, il peut se révéler utile d'afficher uniquement les messages les plus récents et d'afficher le message le plus récente en premier. Pour ce faire, il suffit de modifier la requête du magasin de données. Vous interrogez une requête via l'interface JDO à l'aide du langage JDOQL, un langage de requête de type SQL qui permet d'extraire les objets de données. Dans notre page JSP, la ligne ci-dessous définit la chaîne de requête JDOQL : String query = "select from " + Greeting.class.getName(); En d'autres termes, la requête JDOQL est la suivante : select from guestbook.Greeting Cette requête interroge le magasin de données pour chaque instance de la classe Greeting enregistrée jusqu'à présent. Une requête peut indiquer l'ordre dans lequel les résultats sont renvoyés en termes de valeurs de propriété. Pour extraire l'ensemble des objets Greeting dans l'ordre inverse de l'ordre dans lequel ils ont été postés (du plus récent au plus ancien), vous devez utiliser la requête suivante : select from guestbook.Greeting order by date desc Une requête permet également de limiter le nombre de résultats renvoyés. Pour extraire uniquement les 5 messages de bienvenue les plus récents, utilisez order by et range, comme suit : select from guestbook.Greeting order by date desc range 0,5 C'est ce que nous allons maintenant faire pour l'application du livre d'or. Dans guestbook.jsp, remplacez la définition query par : String query = "select from " + Greeting.class.getName() + " order by date desc range 0,5"; Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 19/23 Architectures réparties et Cloud Computing Postez plus de 5 messages de bienvenue dans le livre d'or. Seuls les 5 messages les plus récents s'affichent, dans l'ordre chronologique inverse. Pour plus d'informations sur les requêtes et le langage JDOQL, consultez la section Requêtes et index. Étapes suivantes... Chaque application Web renvoie du code HTML dynamique à partir du code d'application, via des modèles ou d'autres mécanismes. La plupart des applications Web ont également besoin de diffuser du contenu statique, tel que des images, des feuilles de style CSS ou des fichiers JavaScript. Pour plus d'efficacité, App Engine traite les fichiers statiques de manière différente dans la source d'application et les fichiers de données. Nous allons maintenant créer une feuille de style CSS pour l'application, sous forme de fichier statique. Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 20/23 Architectures réparties et Cloud Computing Utilisation des fichiers statiques Certains cas de figure nécessitent l'affichage de fichiers statiques directement dans le navigateur. Les images, les feuilles de style CSS, les codes JavaScript, les films et les animations Flash sont généralement diffusés directement dans le navigateur. Pour plus d'efficacité, App Engine diffuse les fichiers statiques à partir de serveurs différents de ceux qui appellent les servlets. Par défaut, App Engine définit tous les fichiers du fichier d'archives WAR en tant que fichiers statiques, à l'exception des fichiers JSP et des fichiers contenus dans WEB-INF/. Toutes les requêtes d'URL dont le chemin correspond à un fichier statique affichent le fichier directement dans le navigateur et ce, même si le chemin correspond également à un mappage de filtre ou de servlet. Vous pouvez définir quels fichiers sont traités par App Engine en tant que fichiers statiques à l'aide du fichier de configuration appengine-web.xml. Améliorons maintenant l'apparence de notre livre d'or à l'aide d'une feuille de style CSS. Dans cet exemple, nous n'allons pas modifier la configuration des fichiers statiques. Pour plus d'informations sur la configuration des fichiers statiques et des fichiers de ressources, consultez la section Configuration de l'application Java. Feuille de style simple Dans le répertoire war/, créez un répertoire appelé stylesheets/. Dans ce répertoire, créez un fichier nommé main.css avec les éléments suivants : body { font-family: Verdana, Helvetica, sans-serif; background-color: #FFFFCC; } Modifiez le fichier war/guestbook.jsp et insérez les lignes ci-dessous juste après la ligne <html> située au début : <html> <head> <link type="text/css" rel="stylesheet" href="/stylesheets/main.css" /> </head> <body> ... </body> </html> Accédez à http://localhost:8888/. La nouvelle version utilise la feuille de style. Étapes suivantes... Le moment est venu de diffuser votre application au monde entier. Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 21/23 Architectures réparties et Cloud Computing Transfert de votre application Vous créez et vous gérez des applications dans App Engine via la console d'administration. Une fois l'identifiant de votre application enregistré, utilisez-le pour transférer votre application vers App Engine à l'aide du plug-in Eclipse ou d'un outil de ligne de commande livré avec le kit de développement de logiciels (SDK). Remarque : Vous pouvez supprimer un identifiant d'application que vous avez enregistré, mais vous ne pourrez plus le réutiliser par la suite. Vous pouvez ignorer les étapes ci-dessous si vous ne souhaitez pas enregistrer d'identifiant pour le moment. Enregistrement de l'application Pour créer et gérer des applications Web App Engine, servez-vous de la console d'administration App Engine qui est accessible à l'adresse suivante : https://appengine.google.com/ Connectez-vous à App Engine à l'aide de votre compte Google. Si vous n'en possédez pas, vous pouvez créer un compte Google avec une adresse e-mail et un mot de passe. Pour créer une application, cliquez sur le bouton "Create an Application" (Créer une application). Suivez les instructions pour enregistrer un identifiant d'application, le nom unique de l'application concernée. Si vous optez pour le nom de domaine gratuit appspot.com, l'URL complète de votre application sera http://application-id.appspot.com/. Vous pouvez également acheter un nom de domaine de premier niveau pour votre application ou en utiliser un que vous avez déjà enregistré. Dans le fichier appengine-web.xml, remplacez la valeur de l'élément <application> par l'identifiant d'application que vous avez enregistré. Transfert de l'application Vous pouvez transférer votre application à l'aide d'Eclipse ou d'une invite de commande. Transfert à l'aide d'Eclipse Vous pouvez transférer vos fichiers et votre code d'application à partir d'Eclipse via le plug-in Google. Pour transférer votre application depuis Eclipse, cliquez sur le bouton de déploiement App Engine situé sur la barre d'outils : Identifiez-vous à l'aide du nom d'utilisateur (adresse e-mail) et du mot de passe de votre compte Google, puis cliquez sur le bouton Transférer. Eclipse extrait l'identifiant d'application et les informations de version à partir du fichier appengine-web.xml, puis transfère le contenu du répertoire war/. Transfert à l'aide d'une invite de commande Vous pouvez transférer vos fichiers et votre code d'application à partir de l'invite de commande fournie dans le SDK appelée appcfg.cmd (Windows) ou appcfg.sh (Mac OS X, Linux). Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 22/23 Architectures réparties et Cloud Computing AppCfg est un outil multifonctions conçu pour interagir avec votre application sur App Engine. La commande utilise le nom d'une action, le chemin d'accès au répertoire war/ de votre application, ainsi que d'autres options. Pour transférer les fichiers et le code d'application vers App Engine, utilisez l'action update. Pour transférer l'application sous Windows, saisissez : ..\appengine-java-sdk\bin\appcfg.cmd update war Pour transférer l'application sous Mac OS X ou Linux, saisissez : ../appengine-java-sdk/bin/appcfg.sh update war À l'invite, entrez votre nom d'utilisateur et votre mot de passe Google. Accès à l'application Vous pouvez maintenant voir votre application en cours d'exécution sur App Engine. Si vous avez configuré un nom de domaine appspot.com gratuit, l'URL de votre site Web commence par l'identifiant de votre application : http://application-id.appspot.com/ Daniel Tschirhart - Architectures réparties et Cloud Computing - Utilisation de Google App Engine en Java V1.2011 23/23