Réutilisation & Composants Intervenant : André Morassut TD – TP 2014 2014-2015 Objectifs - - Mise en place d’un projet JAVA J2EE Utilisation de MAVEN pour la définition des composants/dépendances à utiliser Utilisation de JPA (Hibernate) pour la mise en place d’un schéma de persistance Utilisation d’une implémentation « JAX-RS » : Jersey Mise en place de « patrons » réutilisables pour traiter les classes de traitement comme des composants o Définition d’objets métiers o Définition des accès aux données o Définition des services Mise en place de tests unitaires Thème des travaux Mise en place d’un serveur permettant la gestion de « bookmarks » (favoris) : ajouter, supprimer, modifier des favoris auxquels nous adjoindront diverses données. Les favoris sont composés d’un nom obligatoire et d’une description optionnelle définis par l’utilisateur, données auxquelles s’ajoute l’URL du favori ainsi qu’un compteur de vues. Chaque favori peut se voir associer une liste, éventuellement vide, de « tags ». Ces tags sont de simples libellés. Chaque favori garde trace de l’utilisateur qui l’a ajouté. La mise en place d’une couche REST conduirait à la définition des services suivants : En lecture : - GET [server]/bookmark/{id} GET [server]/bookmark/{id}/tags GET [server]/bookmark/all GET [server]/tag/{id} GET [server]/tag/all En écriture : - POST [server]/bookmark/ GET [server]/bookmark/tag/ DELETE [server]/bookmark/{id} DELETE [server]/bookmark/tag/{id} DELETE [server] /tag/{id} Cette liste n’est pas exhaustive, nous aurions pu avoir DELETE [server]/bookmarks/all, MOVE [server]/bookmark/tags/{idbookmarkFrom}/{idbookmarkTo}… GMIN30F/MORASSUT Page 2 Étapes de mise en place - - - Partie 1 : o Mise en place de l’environnement de développement o Mise en place d’un projet MAVEN o Définir des dépendances o Configurer une webapplication o Poser un service « helloworld » JERSEY Partie 2 : o Définition de la persistance JPA o Mise en place d’objets métier o Mise en place de DAO & services o Mise en place de services REST d’interrogation Partie 3 : o Suite mise en place couche REST o Mise en place de tests unitaires Outils - Eclipse IDE GlassFish 4.0 (J2EE 7.0 compliant) Hibernate 3.x Spring 3.x JERSEY MAVEN2 Junit3/4 GMIN30F/MORASSUT Page 3 PARTIE 1 Mise en place de l’environnement & premier service REST Présentation Durant cette première partie, nous allons mettre en place le « squelette » du projet et configurer SPRING comme JERSEY afin de pouvoir déployer des services JAX-RS via un serveur d’application JAVAEE GlassFish. JERSEY est une « quality reference implementation » de JAX-RS qui est intégrée à GlassFish selon les éditions. Cette librairie nous permettra d’exposer un premier service REST. Adresses utiles : - Maven : http://maven.apache.org/ Glassfish : https://glassfish.java.net/ Jersey : https://jersey.java.net/ JAX-RS : https://jax-rs-spec.java.net/ Étapes de mise en place Préparation de l’IDE ECLIPSE Définir un nouveau workspace Par le menu des préférences (Windows > Preferences), définir : o Encoding : UTF-8 o Pointer sur un JDK au niveau de la configuration JAVA Vérifier la présence d’un plugin maven (Windows > Preferences > Maven) Mise en place de MAVEN Copier MAVEN Le dezipper à un emplacement approprié pour une librairie externe Modifier « settings.xml », intégrer : <repository> <id>codehausSnapshots</id> <name>Codehaus Snapshots</name> <releases> <enabled>false</enabled> <updatePolicy>always</updatePolicy> <checksumPolicy>warn</checksumPolicy> </releases> GMIN30F/MORASSUT Page 4 <snapshots> <enabled>true</enabled> <updatePolicy>never</updatePolicy> <checksumPolicy>fail</checksumPolicy> </snapshots> <url>http://snapshots.maven.codehaus.org/maven2</url> <layout>default</layout> </repository> IMPORTANT : o Pour que MAVEN puisse fonctionner en salle machines (TP), il faut déclarer le proxy de l’université. Si vous utilisez votre propre machine, ça n’est pas nécessaire. o Pour déclarer le proxy, ajouter les déclarations suivantes dans les balises <proxies></proxies> de votre fichier « settings.xml » positionné dans le répertoire « conf » de votre installation MAVEN : <proxy> <protocol>http</protocol> <host>proxy.info-ufr.univ-montp2.fr</host> <port>3128</port> </proxy> Configurer MAVEN dans ECLIPSE o Ouvrir le menu des préférences globales : Window > Preferences o Ajouter une installation MAVEN pointant sur le répertoire où vous avez dézippé les binaires de MAVEN Aller dans « Installations » de la section « Maven » Utiliser le bouton « Add… » Faire pointer « Global settings from installation directory » sur le fichier « settings.xml » dans le sous-répertoire « conf » du répertoire où vous avez copié Maven Préparation du projet de développement Définir un nouveau projet o Menu File > New… o Choisir « Maven project » o Dans la fenêtre de configuration, sélectionner « create a simple project » afin de ne pas avoir l’étape de sélection d’un « archetype » o Important. Renseigner les informations de classification de projet MAVEN Group id = fr.tp.[votre nom de famille, simplifié s’il n’est pas au standard JAVA].rest Artifact id = RestBookmarkManager Version : 1.0-SNAPSHOT Name, Description libres GMIN30F/MORASSUT Page 5 o Packaging : war Pas de « parent project » Vous devriez obtenir l’arborescence suivante : [Projet] |+-src | +-main | +-java | +-resources | +-webapp | +-test | +-java | +-resources +-target +-pom.xml Nb. Si des répertoires sont manquants, les créer à la main via le menu File > new > Folder ou File > New > package, afin de parvenir à la structure décrite. Configuration du projet de développement : SPRING, JERSEY Nous allons intégrer des dépendances au projet, ceci se réalise par l’inclusion de clauses dans le fichier pom.xml Les clauses indiquées dans la suite du document doivent être intégrées dans <dependencies></dependencies> Les propriétés utilisées (syntaxe du type ${nomPropriete}) sont intégrables dans le fichier MAVEN : <properties> <org.springframework.version>3.0.3.RELEASE</org.springframework .version> <spring-security.version>3.0.2.RELEASE</springsecurity.version> <jersey.version>1.16</jersey.version> </properties> Ajouter des librairies au projet (rappel : entourer l’ensemble des déclarations <dependency> par des balises <dependencies>): o Ajout de SPRING/HIBERNATE <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> GMIN30F/MORASSUT Page 6 <artifactId>spring-expression</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>${spring-security.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring-security.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>${spring-security.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> GMIN30F/MORASSUT Page 7 <artifactId>spring-security-web</artifactId> <version>${spring-security.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>3.6.4.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.2.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-commonsannotations</artifactId> <version>3.2.0.Final</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.0.GA</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>com.thoughtworks.xstream</groupId> <artifactId>xstream</artifactId> GMIN30F/MORASSUT Page 8 <version>1.3.1</version> </dependency> o Ajout de JERSEY <!-- Jersey --> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>${jersey.version}</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-json</artifactId> <version>${jersey.version}</version> </dependency> <!-- Jersey Spring --> <dependency> <groupId>com.sun.jersey.contribs</groupId> <artifactId>jersey-spring</artifactId> <version>${jersey.version}</version> <!-- Exclusion explicite des dépendances SPRING (par défaut spring 2.5 mais compatible 3.X --> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </exclusion> <exclusion> GMIN30F/MORASSUT Page 9 <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> </exclusion> </exclusions> </dependency> Ces librairies vont nous permettre d’utiliser : - JERSEY via SPRING pour la définition d’un « rest service » de test (type « helloworld ») Plus tard dans le TP, Hibernate comme « JPA PROVIDER ». Hibernate sera l’implémentation choisie pour le standard Java EE de persistance. Nb. Il y a, via cette configuration, plus de dépendances que nécessaire. C’est volontaire afin de vous permettre éventuellement d’étendre la base que vous obtiendrez à la fin de ce TP, par exemple pour ajouter une couche IHM JSF. Point sur les éléments réalisés A ce niveau, nous avons un projet vide au format MAVEN. Le pom.xml est configuré et permet la gestion automatique des dépendances ainsi que du cycle de vie du projet. Si vous cliquez-droit sur le projet, vous aurez une section « maven » qui présentera les opérations courantes. Par exemple : - « clean » : suppression des répertoires temporaires, de sortie de compilation, etc. « install » : compilation, exécution des tests, packaging et déploiement dans le « repository local » « package » : compilation, exécution des tests et réalisation du package (jar, war, ear ou autre…) « deploy » : transfert du package vers un entrepôt etc. Cette base de projet standard se retrouve pour tous les types d’applications Java EE ouverts à Maven et Spring. Sur celle-ci, il est possible de réaliser une webapplication comme une application système en ligne de commande en disposant d’un environnement, d’une structure qui est toujours la même. Pour la suite, nous allons configurer SPRING et JERSEY de manière à pouvoir définir des services REST. GMIN30F/MORASSUT Page 10 Configurer Spring Créer un nouveau fichier « applicationContext.xml » dans le répertoire « [projet]\src\main\webapp\WEB-INF » Y intégrer le contenu suivant : <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema /beans http://www.springframework.org/schema/beans/spring-beans3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> </beans> Nb. Le fichier est vide d’instructions utiles pour le moment, il servira en partie 2 à définir les fichiers de configuration permettant de déclarer DAO et services. Nb. Les déclarations de namespaces sont retrouvables via la documentation de SPRING Configurer une « web application » Ajouter un web.xml au projet o Créer un nouveau fichier « web.xml » dans « [projet]\src\main\webapp\WEB-INF » o Y intégrer le contenu initial suivant : <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <context-param> GMIN30F/MORASSUT Page 11 <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param> <listener> <listenerclass>org.springframework.web.context.ContextLoaderListener</listene r-class> </listener> </web-app> Nb. Ce fichier est utilisé par les serveurs (serveurs http classiques ou serveurs JAVA EE) pour « découvrir » une application. Par ce fichier, on pourra notamment définir la page d’accueil, des servlets, etc. Ici, nous configurons SPRING. Configuration du serveur Java EE Configurer GLASSFISH sous Eclipse o Ouvrir la vue « server » o Configurer une nouvelle instance de Glassfish Clic droit dans la vue « server », sélectionner « New server » Deux méthodes : • Si Glassfish est déjà installé o Sélectionner « Glassfish 4.0 » dans la liste o Faire pointer sur l’installation existante dans la fenêtre suivante, champ « Domain Directory » (utiliser le domain1 par défaut si possible) • Si Glassfish n’est pas déjà installé o Il est possible de télécharger l’adaptateur directement, pour cela il faut cliquer sur le lien « download additional server adapters » o Choisir Glassfish 4 Dans tous les cas, si la définition d’un compte administrateur vous est demandée, conserver les informations par défaut, c'est-à-dire : • Username : « admin » • Password : [laisser le champ vide] Point sur les éléments réalisés Comme nous allons réaliser une application déployable dans un serveur Java EE, nous avons modifié notre projet de manière à définir une webapplication. Nous avons ajouté un élément de configuration SPRING qui va nous permettre de mettre en place, dans la suite des réalisations, des comportements automatiques. Enfin, nous avons configuré Glassfish : ce serveur Java EE accueillera les déploiements de notre application. GMIN30F/MORASSUT Page 12 Intégration d’un service « Hello World » Créer un package « rest » où vous intègrerez les classes exposant les services REST Créer une nouvelle classe « Helloworld » Utiliser les annotations @Path (sur la classe), @Context (injection d’un objet UriInfo), @GET (sur la méthode), @Produces (sur la méthode) afin de définir une méthode « public String getHtml() » retournant un simple HTML avec une chaîne par défaut (Hello World ! convient très bien.) Exemple d’implémentation : /** * Root resource (exposed at "helloworld" path) */ @Path("helloworld") public class HelloWorld { @Context private UriInfo context; /** Creates a new instance of HelloWorld */ public HelloWorld() { } /** * Retrieves representation of an instance of helloWorld.HelloWorld * @return an instance of java.lang.String */ @GET @Produces("text/html") public String getHtml() { return "<html lang=\"en\"><body><h1>Hello, World!!</h1></body></html>"; } } Remarques : - - @Path peut être aussi utilisé sur les méthodes. Ainsi, si l’on avait ajouté « @Path(« test ») » sur la méthode « getHtml », le service aurait été accessible via « [server]/helloworld/test » au lieu de « [server]/helloworld » @Context est nécessaire au fonctionnement de JERSEY Le constructeur sans argument permet d’être certain du fait que l’instanciation par réflexion sera possible (c’est JERSEY qui s’occupera d’instancier notre classe) Tester le service REST « Hello world » Aller dans la vue serveur Sur le serveur « Glassfish », cliquer droit et publier votre module web o Si le serveur ne connaît pas votre module, clic droit sur celui-ci et choisir « Add and remove… ». Dans la fenêtre, sélectionnez votre module et faites le basculer dans la liste des modules configurés o Si le serveur ne démarre pas à cause d’un utilisateur ou mot de passe invalider, vous pouvez double cliquer sur le serveur dans la vue serveur et une page de GMIN30F/MORASSUT Page 13 configuration s’ouvrira. Vous pouvez l’utiliser pour mettre à jour l’utilisateur/mot de passe (par défaut, utilisateur « admin » et mot de passe laissé vide) Le serveur démarre, suivre l’instanciation des services via la console Eclipse Quand le serveur est démarré, utiliser un navigateur web afin d’afficher l’URL « http://localhost:8080/RestBookmarkManager/ws/helloworld » : vous devriez constater l’affichage du HTML que vous avez défini dans votre serveur REST Point sur les éléments réalisés Tous les éléments mis en place nous ont permis de définir un service REST de manière très minimale. SPRING et Glassfish vont s’occuper de gérer les ressources, les connexions, etc. alors que nous pouvons nous concentrer sur le service proprement dit. Ainsi, dans cette étape, nous avons notre application déployée qui est capable de recevoir des requêtes et de répondre. Pour les étapes suivantes, nous allons doter notre application d’une couche de persistance à la norme Java EE : JPA GMIN30F/MORASSUT Page 14