jeudi 8 juillet 2010

New versions of GWT

GWT 2.0.4 is available

Apple has recently released Safari 5, which include a bug where non-integral right-shifts were not being evaluated properly.
In case you experienced this bug, you need to recompile and redeploy your application.
The release is available here.

GWT 2.1 Milestone 2

This new version brings some improvement of the previous milestone:
  • simplification the process of configuring a RequestFactory
  • made record creation within a RequestFactory more extensible
  • moved project out of bikeshed
A full list of new festure and bug fixed can be found here.
The milestone is available here.

jeudi 10 juin 2010

Spring 3.0 et Rest

C'est seulement depuis la version 3.0 de Spring que le MVC supporte les services Rest. Biensur, le framework intègre les principales implémentations tel Jersey ou Restlet, mais dans la partie concernant les web services. La décision d'ajouter une implémentation Rest dans Spring MVC vient de l'orientation prise par le framework:
  • les méthodes des contrôleurs fournissent des vues en résultat
  • des annotations trés similaires à celles de Rest permettent:
    • le binding d'une URL vers un contrôleur
    • le binding des paramétres vers les arguments des méthodes d'un contrôleur

Configuration de base

Configurer l'application web

Pour commencer, il faut déclarer le DispatcherServlet dans le fichier de configuration de l'application web: web.xml.

<web-app>

<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/app-config.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>

</web-app>

En lui spécifiant le paramètre contextConfigLocation, la servlet va charger le context Spring a sa création. Le fichier de context se trouve: /WEB-INF/spring. La servlet doit mapper toutes les URLs du type:

<app_context>/services/*

Configuration Spring

La configuration Spring se fait en deux fichiers différents:

  • le context principal, le fichier app-config.xml, qui contient la configuration du backend: DAO, services et mappers.
  • le context MVC, dans le fichier mvc-config.xml, qui contient la configuration... du MVC.

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">


<mvc:annotation-driven />

</beans>

Cette configuration permet d'utiliser l'annotation @Controller pour déclarer les beans gérés par Spring MVC.

Implémentation d'un contrôleur

L'exemple suivant se base sur la gestion d'objets SampleBean:

public class SampleBean {

private String name;
private long id;
}

Et utilise le SampleController pour effectuer une recherche par id sur les SampleBean.

@Controller
@RequestMapping("/sample")
public class SampleController {

@RequestMapping(value="{id}", method=RequestMethod.GET)
public @ResponseBody SampleBean get(@PathVariable long id) {
return persistence.get(id);
}
}
  1. L'annotation @RequestMapping("/sample") sur la classe permet de mapper toutes les requêtes du type /services/sample sur ce contrôleur. /services étant l'URL sur lequel le DispatcherServlet est mappé.
  2. L'annotation @RequestMapping(value="{id}", method=RequestMethod.GET) sur la méthode get spécifie cette méthode sera appelé pour toutes les URL pouvant mapper avec /services/sample/4 pour les requêtes dont la méthode est GET.
  3. L'annotation @PathVariable permet de spécifier que l'une des valeurs ente {} de l'URL doit être mapper sur cette variable.
  4. @ResponseBody permet de déclarer que la valeur de retour de la méthode sera renvoyer dans le corps de la réponse. Reste à le convertir dans un format quelconque.

Mapper le résultat vers un format spécifique

Pour mettre en place la convertion, il faut configurer un bean de type ContentNegotiatingViewResolver. En Rest, l'opération de mapping des valeurs de retour et des paramètres vers des objets s'appel: négociation. La négociation se fait en ce basant sur la valeur du header Accept de la requête. Pour cet exemple, le mapping se fera vers du JSon. le header Accept aura donc pour valeur: application/json. Spring fournit parmis ces dépendances, le parseur Jackson, qui est utiliser dans ce qui suit:

 <bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" p:order="1">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>

La configuration se fait en spécifiant les formats supportés avec l'attribut mediaTypes et les implémentations des mappers ave la propriété defaultViews. La propriété mediaTypes correspond au contenu du header Accept de la requête reçu par le DispatcherServvlet.

vendredi 28 mai 2010

Intégration Eclipse Mylyn - Redmine

Installation du plugin

Mylyn est un plugin Eclipse de gestion de tâches. Nous allons expliquer ici comment connecter Mylyn à Redmine en utilisant les connecteurs aux repository web.

Les connecteurs ne font pas partis de l'installation par défaut de Mylyn. Vous devez donc installer ces extensions en enregistrant le site suivant dans Eclipse: http://download.eclipse.org/tools/mylyn/update/incubator.

Création d'un Task Repository

  1. Ouvrir la vue Task Repository
  2. Click droit sur la liste des task repositories list et clicker sur Add task repository
  3. Choisir Web Template (Advanced) et clicker sur Next
  4. Configuration du repository:
Server:                 http://www.redmine.org/ -- Remplacer cette URL par celle de votre installation Redmine
Task URL: ${serverUrl}/issues/show/
New task URL: ${serverUrl}/projects/project/issues/new -- Remplacer project par le nom du projet
Query request URL: ${serverUrl}/issues
Query pattern: <td class="subject">.*?<a href="/issues/show/(\d+)">(.+?)</a></td>
Login request URL: ${serverUrl}/login?username=${userId}&password=${password} [POST]

Vous pouvez remplacer le champ Query request URL par la requête suivante si vous ne voulez que les tâches qui vous sont assignées:

${serverUrl}/issues?set_filter=1&assigned_to_id=me

La requête suivante lit le Status, le Owner et le Tracker (Mylyn 3.2.1) :

<td class="tracker">({Type}.+?)</td><td class="status">({Status}.+?)</td>.+?<td class="subject"><a href=".*?/issues/show/({Id}\d+)">({Description}.+?)</a></td><td class="assigned_to"><a>({Owner}.+?)</a></td>

Le status sera affiché comme "complete" ou "uncomplete" par Eclipse.

Création d'une requête

  • Dans la liste des tâches, click droit, puis choisir New -> Query...
  • Ensuite sélectionner le repository

samedi 8 mai 2010

Flexmojos et les charts

Une configuration standard du plugin Flexmojos ne permet pas de compiler des charts. La compilation renvoie l'erreur suivante:

[ERROR] Could not resolve <mx:linechart> to a component implementation.

Les dépendances nécessaires ne sont pas disponibles sur un repo Maven. Il faut les ajouter dans le repo local à partir d'une installation du SDK Flex.

Pour commencer, il faut ajouter les dépendances dans le fichier Maven:

<dependency>
<groupid>com.adobe.flex.sdk</groupid>
<artifactid>datavisualization</artifactid>
<type>swc</type>
<scope>merged</scope>
<version>3.2.0.3958</version>
</dependency>
<dependency>
<groupid>com.adobe.flex.sdk</groupid>
<artifactid>datavisualization</artifactid>
<version>3.2.0.3958</version>
<type>rb.swc</type>
<classifier>en_US</classifier>
</dependency>

La seconde dépendances permet d'éviter l'erreur de compilation:

Unable to resolve resource bundle "charts" for locale "en_US".

Ensuite, il faut rajouter les dépendances dans le repo Maven local:

mvn install:install-file -DgroupId=com.adobe.flex.sdk
-DartifactId=datavisualization
-Dversion=3.2.0.3958
-Dpackaging=swc
-Dfile="/Applications/Adobe Flex Builder 3/sdks/3.2.0/frameworks/libs/datavisualization.swc"

Ensuite, il faut rajouter le ressource bundle:

mvn install:install-file -DgroupId=com.adobe.flex.sdk
-DartifactId=datavisualization
-Dversion=3.2.0.3958
-Dclassifier=en_US
-Dpackaging=rb.swc
-Dfile="/Applications/Adobe Flex Builder 3/sdks/3.2.0/frameworks/local/locale/en_US/datavisualization_rb.swc"

Si le scope de l'artifact datavisualization n'est pas mis à merge, l'application compilera, mais l'erreur suivante arrivera à l'exécution:

VerifyError: Error #1014: Class mx.charts::LineChart could not be found.

Il reste encore un problème à résoudre: la licence. Avec la configuration actuelle, les charts vont être affichés avec le message: Trial Visualization.

Il faut configurer le pom pour qu'il utilise la licence à la compilation:

<build>
<sourcedirectory>src/main/flex</sourcedirectory>
<plugins>
<plugin>
<groupid>org.sonatype.flexmojos</groupid>
<artifactid>flexmojos-maven-plugin</artifactid>
<version>3.5.0</version>
<extensions>true</extensions>
<configuration>
<contextroot>/appcontext</contextroot>
<debug>true</debug>
<licenses>
<flexbuilder3>nnnn-nnnn-nnnn-nnnn-nnnn-nnnn</flexbuilder3>
</licenses>
<sourcefile>App.mxml</sourcefile>
<targetplayer>9.0.124</targetplayer>
</configuration>
<dependencies>
<dependency>
<groupid>com.adobe.flex</groupid>
<artifactid>license</artifactid>
<type>jar</type>
<version>3.2.0.3958</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

La dépendance ne doit être rajouté qu'au plugin, pas au projet.

Le jar nécessaire à la licence n'est pas disponible non plus sur un repo maven, il faut donc l'installer à partir d'une installation Flex avec la commande suivante:

mvn install:install-file
-DgroupId=com.adobe.flex
-DartifactId=license
-Dversion=3.2.0.3958
-Dpackaging=jar
-Dfile="C:\Program Files\Adobe\Flex Builder 3 Plug-in\sdks\3.2.0\lib\license.jar"

Aprés une compilation, les charts s'afficheront sans le message de trial.

vendredi 30 avril 2010

Intégration Spring Flex

Spring Source a présenté l'année dernière à SpringOne, son projet d'intégration Spring et Flex, Spring Flex. Ce projet veut simplifier la mise en place d'un backend Spring derrière BlazeDS, le message broker free de Adobe. L'exemple suivant décrit les fichiers de nécessaires pour une configuration standard avec des Remote Object.

Fichier Maven

Le plugin utilisé pour compiler Flex est FlexMojos.
Sans passer par l'intégration de Spring Flex, il faut déclarer chaque jar BlazeDS comme dépendance, ce qui fait une demi douzaine de dépendances au total, Adobe n'ayant pas géré les dépendances entre les modules de BlazeDS.
Le fichier Maven de Spring Flex référence tous les modules nécessaires de BlazeDS.

<dependency>
<groupid>org.springframework.flex</groupid>
<artifactid>spring-flex</artifactid>
<version>1.0.3.RELEASE</version>
<type>jar</type>
<scope>runtime</scope>
</dependency>

Cette version de Spring Flex est dépendante de la version 2.5.6 de Spring.

Structure du WAR

L'application est configurée pour utiliser les répertoires suivant sous le répertoire WEB-INF:
  • conf: configuration SpringFlex
  • flex: configuration BlazeDS
  • spring: configuration vers le backend

Déclaration dans le fichier web.xml

La configuration de Spring se fait en utilisant les fonctionnalités de Spring MVC. Le chargement du context Spring se fait en déclarant les contextes du backend a charger et le listener de chargement.

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/*-context.xml
</param-value>
</context-param>

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

Ensuite, le DispatcherServlet est déclarer pour matcher toutes les requêtes vers le message broker. Il doit être initialisé avec un fichier de contexte Spring configurant l'intégration SpringFlex.

<servlet>
<servlet-name>flex</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/web-application-config.xml</param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-name>flex</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>

Configuration de BlazeDS

La configuration de BlazeDS passe par le fichier de contexte Spring utilisé par le DispatcherServlet: /WEB-INF/config/web-application-config.xml. Il ne fait que déclarer la configuration du message broker. Dans notre cas, la configuration par défaut est suffisante.
Le message broker est configurer pour charger le fichier de configuration des services BlazeDS
dans: WEB-INF/flex/services-config.xml.

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:flex="http://www.springframework.org/schema/flex" 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-2.5.xsd
http://www.springframework.org/schema/flex
http://www.springframework.org/schema/flex/spring-flex-1.0.xsd">

<flex:message-broker/>

</beans>

C'est dans ce fichier que l'on pourra déclarer les Remote Object.

Le fichier des services BlazeDS est réduit au minimal pour une configuration standard. Dans notre cas, il n'est pas nécessaire d'avoir d'autres fichiers de configuration.
Il suffit de déclarer le channel par défaut et de le configurer.

<services-config>

<services>
<default-channels>
<channel ref="my-amf">
</default-channels>
</services>

<channels>
<channel-definition id="my-amf"
class="mx.messaging.channels.AMFChannel">
<endpoint
url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"
class="flex.messaging.endpoints.AMFEndpoint" />
</channel-definition>
</channels>
</services-config>

Déclaration des Remote Object

SpringFlex offre deux façons de déclarer des Remote Object:
  • Par configuration
  • Par annotation

Par configuration

Le namespace flex apporte l'élément remoting-destination qui permet de référencer un bean Spring et de l'exposer comme Remote Object. L'attribut ref permet de référencer un bean par son id. Et l'attribut destination-id permet de déclarer le nom du Remote Object coté Flex. Par défaut, destination-id est égale à l'id du bean.

<flex:remoting-destination id="userService" ref="userService"/>

Par annotation

L'annotation RemotingDestination de SpringFlex permet de déclarer au niveau de la classe d'un bean, qu'il doit être exposé à Flex via le message broker. Elle permet également de déclarer la destination, mais par défaut, il s'agira du nom du bean avec la première lettre en minuscule.
Cet approche couple directement les beans du backend à la technologie du frontend, ce qui, dans le cas d'un changement de technologie web, obligera les développeurs à garder des dépendances inutiles.