GWT

De EjnTricks

Logo GWT.png

Cet article présente le développement d'application avec le framework GWT de Google Apps. Les projets seront construits au sein de l'IDE Eclipse.

Création du projet

Plugin Eclipse GoogleApps

Le moyen le plus rapide pour créer un projet est d'utiliser le plugin sous Eclipse, dont l'utilisation est détaillé dans l'article Utilisation Eclipse GWT Plugin.

Malgré sa grande facilité, l'utilisation de cette méthode est assez restrictive. Par exemple dans le cadre d'une intégration continue, les outils type Jenkins ne propose pas de plugin. De plus, les différentes librairies sont directement incluses dans le projet, au niveau du répertoire WEB-INF/lib. Donc dans le cas d'une gestion de source, avec SVN par exemple, tous les fichiers devront être commités, entraînant une consommation inutile d'espace disque.

Enfin, l'exécution de l'application, dans la phase de développement, est assez adhérente au plugin. Typiquement, le projet n'est pas vu comme un projet Web, et ne peut donc pas être inclus dans un serveur Tomcat embarqué sous Eclipse

Cependant, elle peut être très utile afin d'identifier des paramètres par défaut dans les différents fichiers de configuration.

Création artefact Maven

La manière la plus simple consiste en la création du projet à l'aide du plugin maven-archetype-plugin, détaillé dans l'article Plugin Maven GWT.

Il ne faut pas oublier de modifier les versions de compilations dans le fichier généré.

L'utilisation du plugin engendre la création des fichiers pour Eclipse. Il peut donc être importé directement dans Eclipse. Cependant, toutes les librairies ne sont pas injectés dans le projet, comme le framework Junit.

Pour y remédier, il faut lancer la commande mvn eclipse:eclipse afin de construire de nouveau le projet.

A noter, il ne faut pas oublier de spécifier l'argument wtpversion avec la version 2.0 afin que le projet soit bien géré comme un projet Web, voir article Eclipse Maven Plugin.


Après rafraîchissement du projet, les erreurs sont résolues. Seule une information sur le répertoire de compilation est affichée.


Cependant, ce message doit être considéré comme un "Warning", car l'exécution avec le plugin GWT, ou la publication sous Tomcat sont fonctionnelles.


Intégration de Spring

Configuration projet

L'intégration de Spring avec GWT a été réalisée en se basant sur le lien suivant: http://www.mistra.fr/tutoriels-ria/tutoriel-ria-gwt-2-spring.html

Par défaut, les services sont gérés au sein du projet. Dans une architecture J2EE, il est d'usage d'utiliser Spring afin d'injecter les dépendances. C'est tout à fait approprié lors de la mise en place d'une application GWT. Il serait alors possible de mettre en place des bouchons aux niveaux des DAO par exemple.

Un projet OpenSource est disponible pour la mise en place de Spring dans ce type de développement: http://code.google.com/p/gwtrpc-spring

Cependant, cette librairie ne figure pas dans les dépôts Maven. Le fichier GwtRpcSpring-1.01.zip est téléchargé depuis le site, pour extraire le jar gwtrpc-spring-1.01.jar pour:

  • Soit l'installer manuellement à l'aide de la commande:
#mvn install:install-file -Dfile=gwtrpc-spring-1.01.jar -DgroupId=org.gwtrpcspring 
 -DartifactId=gwtrpcspring -Dversion=1.01 -Dpackaging=jar

Documentation officielle: http://code.google.com/p/gwtrpc-spring/issues/detail?id=6

  • Soit l'installer manuellement dans un serveur type Nexus

Il faut ensuite ajouter dans le pom du projet la dépendance sur ce projet:

    <dependency>
      <groupId>org.gwtrpcspring</groupId>
      <artifactId>gwtrpcspring</artifactId>
      <version>1.01</version>
    </dependency>


Comme le framework Spring est utilisé, il est également nécessaire de placer les dépendances dans le pom, après avoir spécifié la variable spring.version.

    <dependency>
      <artifactId>spring-beans</artifactId>
      <groupId>org.springframework</groupId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <artifactId>spring-context</artifactId>
      <groupId>org.springframework</groupId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <artifactId>spring-core</artifactId>
      <groupId>org.springframework</groupId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <artifactId>spring-web</artifactId>
      <groupId>org.springframework</groupId>
      <version>${spring.version}</version>
    </dependency>


Implémentation

Avec ce framework, plusieurs modes sont disponibles pour la configuration. Or dans les exemples couramment présentés, seul un service GWT est exposé. Le paragraphe suivant va présenter comment capturer l'ensemble des requêtes.

Modification de web.xml

La première étape consiste à modifier le fichier web.xml. Lors de la création de l'artefact, le contenu suivant a été placé dans le fichier:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

  <!-- Servlets -->
  <servlet>
    <servlet-name>greetServlet</servlet-name>
    <servlet-class>fr.ejn.tutorial.server.GreetingServiceImpl</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>greetServlet</servlet-name>
    <url-pattern>/gwtSpringArtefact/greet</url-pattern>
  </servlet-mapping>

  <!-- Default page to serve -->
  <welcome-file-list>
    <welcome-file>gwtSpringArtefact.html</welcome-file>
  </welcome-file-list>

</web-app>

La définition de la servlet va être supprimée pour intégrer un "dispatcher" Spring.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

	<!-- Servlets -->
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.gwtrpcspring.RemoteServiceDispatcher</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>*.rpc</url-pattern>
	</servlet-mapping>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Default page to serve -->
	<welcome-file-list>
		<welcome-file>gwtSpringArtefact.html</welcome-file>
	</welcome-file-list>

</web-app>

L'ajout d'un listener va permettre de charger les définitions des beans.

Modification des services

Une nouvelle définition de servlet a donc été mise en place, mappée sur *.rpc. Or au niveau de l'annotation RemoteServiceRelativePath de l'interfaceGreetingService, dans le paquet client, il faut modifier la valeur afin que le service soit pris en compte par le dispatcher Spring:

package fr.ejn.tutorial.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

/**
 * The client side stub for the RPC service.
 */
// @RemoteServiceRelativePath("greet")
@RemoteServiceRelativePath("greet.rpc")
public interface GreetingService extends RemoteService {

	String greetServer(String name) throws IllegalArgumentException;

}

Sinon, le service ne sera pas mis à disposition.

Configuration Spring

Par défaut, la configuration Spring se situe dans le fichier applicationContext.xml, qu'il faut déposer dans le répertoire WBE-INF. Dans ce fichier, les "services", se situant dans le paquet server, sont référencés. Il est possible d'utiliser les annotations avec Spring 3.X. Cependant, par conviction, la mise en place du fichier XML est préféré dans le cadre de cet article. Pour les projets générés, le fichier contient 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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	 http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="greetService" class="org.gwtrpcspring.example.server.GreetingServiceImpl" />

</beans>

Modification de l'exemple

Au niveau du service exemple, des informations sont récupérées à partir de this.getServletContext() et this.getThreadLocalRequest(). Or ces fonctions retournent un objet null suite à l'intégration de Spring. La méthode greetServer doit donc être modifiée afin de ne plus provoquer d'anomalie.

@Override
public String greetServer(String input) throws IllegalArgumentException {
	// Verify that the input is valid.
	if (!FieldVerifier.isValidName(input)) {
		// If the input is not valid, throw an IllegalArgumentException back to
		// the client.
		throw new IllegalArgumentException("Name must be at least 4 characters long");
	}

	//String serverInfo = this.getServletContext().getServerInfo();
	String serverInfo = RemoteServiceUtil.getThreadLocalContext().getServerInfo();
	//String userAgent = this.getThreadLocalRequest().getHeader("User-Agent");
	String userAgent = RemoteServiceUtil.getThreadLocalRequest().getHeader("User-Agent");

	// Escape data from the client to avoid cross-site script vulnerabilities.
	input = this.escapeHtml(input);
	userAgent = this.escapeHtml(userAgent);

	return "Hello, " + input + "!<br><br>I am running " + serverInfo 
			+ ".<br><br>It looks like you are using:<br>" + userAgent;
}