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.

lundi 27 juillet 2009

JetBrains Meta Programming System

JetBrains a annoncé la disponibilité de JetBrains MPS , un environement de développment dédié aux DSLs. Cet environement est la réponse, d'aprés cet article, aux besoins, mais également à ladifficulté de développer des DSLs.
Pour rappel, un DSL: Domain Specific Language, est un langage qui doit permettre d'implémenter les régles inhérentes à un domaine précis, comme la finance. Par exemple: un langage mathématique ne doit permettre que d'exprimer des opérations mathématiques.
D'aprés JetBrains, le fait que ce type de langage nesoit pas plus développer est dû à:
  • il n'y a aucun environement qui permet leur développement,
  • les langages étant basés sur des grammaires, combinés plusieurs DSL peut provoquer des ambiguités.
Avec MPS, JetBrains propose de resouvre ces problémes en ce basant, non plus sur des éditeurs traitant du texte, mais sur une représentation arborescente du langage, ce qui écarte tout risque d'ambiguité, puisqu'il n'y a plus de grammaire. D'aprés le site officiel, la faible courbe d'apprentissage et la rapidité de développement que permet l'outil, devrait imposer les DSLs comme une solution viable.

vendredi 24 juillet 2009

Google Plugin For Eclipse

Google fournit un plugin Eclipse pour la création d'applications web basées sur Google Web Toolkit et permettant de déployer les applications sur Google App Engine. Petit tour d'horizon de ce plugin bien pratique.

Installation

Pour installer le plugin, deux URLs sont disponibles suivant la version d'Eclipse:
  • Version 3.3: http://dl.google.com/eclipse/plugin/3.3
  • Version 3.4: http://dl.google.com/eclipse/plugin/3.4
Le plugin install la version 1.6.4 de GWT et la version 1.2.1 du kit Google App Engine par défaut.

Création d'un projet

La création se fait via le wizard en passant par le menu: File > New Project > Web Application Project ou en utilisant le bouton

Le wizard permet d'inclure/exclure GWT et/ou Google App Engine dans le projet. Il inclut par défaut les dernières versions des frameworks. Via les liens Configure SDKs... , il est possible de choisir une autre version du SDK installée sur la station.

GWT

MyTestProject
src/
com/
mytestproject/
MyTestProject.gwt.xml
client/
GreetingService.java
GreetingServiceAsync.java
MyTestProject.java
server/
GreetingServiceImpl.java
war/
MyTestProject.css
MyTestProject.html
WEB-INF/
web.xml
classes/
lib/
...GWT JARs...
Le plugin génère une application de base avec un service RPC de base. L'application permet d'envoyer une message via le service. Et celui-ci renvoi ce message avec des informations sur le serveur.
Pour le service, l'interface, les implémentations coté client et coté serveurs sont générés.

Google App Engine

MyTestProject
src/
log4j.properties
META-INF/
jdoconfig.xml
com/
mytestproject/
MyTestProjectServlet.java
war/
index.html
WEB-INF/
appengine-web.xml
web.xml
logging.properties
classes/
lib/
...App Engine JARs...
L'application générée donne accès à la technologie de persistance DataNucleus utilisée par GAE. Pour la partie présentation, puisque l'application est censé être une appli web, une servlet a été généré.
Le fichier appengine-web.xml permet de configurer le déploiement de l'application. Le fichier jdoconfig.xml contient la configuration du framework DataNucleus.

GWT et GAE

MyTestProject
src/
log4j.properties
META-INF/
jdoconfig.xml
com/
mytestproject/
MyTestProject.gwt.xml
client/
GreetingService.java
GreetingServiceAsync.java
MyTestProject.java
server/
GreetingServiceImpl.java
war/
MyTestProject.css
MyTestProject.html
WEB-INF/
appengine-web.xml
web.xml
logging.properties
classes/
lib/
...App Engine JARs...
...GWT JARs...
L'application offre des fonctionnalités similaires aux deux types de projet précédents.

Exécuter l'application en hosting mode

L'exécution de l'application en hosting mode, mode qui permet d'utiliser le debuger, il suffit de faire click droit sur le projet puis: Run As... > Web Application.
La console, qui permet de monitorer l'activité serveur, s'ouvre:

Puis le hosted browser, un navigateur intégré:

Remarque: il est prévu pour la version 2 de GWT, que le hosted browser soit remplacé par le navigateur par défaut du système hôte.

Déployer l'application Google App Engine

Le déploiement d'une application GAE se fait simplement en clickant sur l'icône pour ouvrir la boite de dialogue:
Il faut posséder un compte GAE pour pouvoir déployer une application, et donc posséder un compte utilisateur Google. Le plugin doit d'abord être configuré avec l'identifiant de l'application GAE: Properties > Google > App Engine > Application ID. Aprés avoir clické sur le bouton Deploy, le plugin compile et package l'application, qui est ensuite envoyée sur la plate forme.
L'application est alors utilisable.

Conclusion

Malgrés la possibilité d'intégrer les outils de GWT tel junitCreator comme outil externe d'Eclipse, je regrette l'abscence de ces outils du plugin. La volonté de Google était apparement de fournir le plus rapidement possible un outil permettant de developper des applications GWT. Du coup, le nice to have a été mis de coté. Ce sera, je l'espére, pour la prochaine version. La raison de cette abscence peut aussi être expliqué par les bugs (dans la version 1.6.4 du SDK) produits par ces scripts.