Archive for the ‘Tutoriel’ Category

Passez vos applications HTML5 sur Android

Monday, April 18th, 2011

Avec la croissance fulgurante ( à 3 chiffres annuel ) des ventes aussi bien sur iPhone que sur Android, les demandes en application mobile natives sont fortes.

Le développement natif a l’avantage d’ une interface utilisateur fluide. Néanmoins la montée en compétence exige au moins quelques mois d’expérience pour des projets relativement courts (en semaines ). Chaque plateforme est spécifique, une expérience sur iPhone n’est pas forcément transférable sur Android et vice versa.

L’ idéal pour le développement multi-plateforme reste l’HTML5 rendu sur le navigateur de l’OS : webkit pour iOS et Android, Firefox pour Meego, Internet Explorer Mobile pour Windows Phone 7. HTML5 reste une solution universelle pour le front-end . Les coûts sont factorisés par le nombre d’OS ciblé.

Il existe des solutions multi plateforme tel que PhoneGap, App Titanium qui mimiquent l’interface utilisateur natif . A la différence de ces outils ,  ce tutorial vous laisse libre sur le choix de votre librairie JavaScript. Les librairies utilisées sont  iUI Project de Joe Hewitt , iWebKit de Jonathan Stark , JQTouch de David Kaneda .

Tutorial

Ce tutorial expose comment utiliser un “wrapper” de l’HTML5 sur Android. En d’autres termes , ce projet embarque de l’ HTML5  dans une application Android .

Commencez un nouveau projet Android sous Eclipse à partir d’android 2.0 ( SDK API >=5 ). Vous disposez déjà d’une application web qui tourne sans serveur. Déposez le dans le répertoire “assets” , c’est ici où tout le site web se trouve avec ses références JavaScript, CSS …

Créez un  nouveau layout “main” où on va introduire une webview . Le layout réprésente la view dans le modèle MVC . Cette webview sera la fenêtre d’entrée pour notre application HTML5 .

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
 
<WebView    android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"    />
 
</LinearLayout>

Dans le code source , créez une classe NaviRay qui hérite d’ Activity . Si vous n’êtes pas familier avec la notion d’activity,  je vous recommande de comprendre son cycle de vie .
La méthode  onCreate initialise le layout “main”  . La  webview pointe dans le dossier assets vers la page index.html

public class NaviRay extends Activity{
 
	private WebView browser;
 
	/** Called when the activity is first created. */
 
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		browser  = (WebView) findViewById(R.id.webview);
		browser.getSettings().setJavaScriptEnabled(true);	
		browser.loadUrl("file:///android_asset/index.html");
	}
}

Dans le manifest , rajoutez la permission android.permission.INTERNET

Ca y est, on peut maintenant accéder à notre site web en local.

Options

Cette application ne comporte qu’une seule Activity . Dans le code source ,  la gestion de l’historique du bouton “back” et le menu sont inclus .

Appels natifs

L’une des restrictions de l’HTML est sans aucun doute l ‘ impossibilité d’utiliser des fonctions natives (GPS , accélèromètre , contacts … ) . Quoi que on peut toujours appeler.
Sans utiliser d’intent , il est possible de passer un appel téléphonique ou d’envoyer des SMS juste avec de l’HTML ( testé sous iPhone et Android )

Pour téléphoner vers

<a href="tel:33-123-456-7891">

Pour envoyer un SMS

<a href="sms:12345678">

Pour envoyer un email

<a href="mailto:ray@ray.com?cc=ex@x.com,lisa@x.com&amp;subject=Sujet HTML5 sur Android!&ampbody=Je viens de tester!">

Code source

Le code source de l’application est disponible à cette url http://code.google.com/p/navray/source
Note : le source est géré sous Mercurial Hg . Pour ceux qui ne l’utilisent pas , le source peut être téléchargé à partir de navray_src_01.zip http://code.google.com/p/navray/downloads/list

Vous pouvez utiliser à différentes expérimentations, il ne reste plus qu’à modifier le contenu du dossier “assets”.

Si vous publiez une application à partir de ce source,  merci de modifier le nom de package Java. En effet le package sert d’identifiant pour une application publiée sur l’Android market.

Gae : Leçons pour celui qui passera après moi ou si vous vous intéressez à GAE, Maven, Jersey, Rest …

Monday, January 24th, 2011

Je vais vous faire part dans ce nouveau billet de mon incommensurable expérience sur GAE et d’un écosystème particulier, le mien. Pour reformuler, ce que je vous propose ici est un REX. J’ai toujours adoré cet acronyme, très parlant, d’une phonétique explosive. C’est le genre de document qui revient vous mordre même une fois que vous l’avez mis à la niche. Pour ceux qui ne connaissent pas, c’est un document que l’on vous demande de rédiger quand vous vous êtes planté pour ne pas vous planter une deuxième fois. De manière plus positive, on a toujours dit que c’est en tombant que l’on apprends à marcher.
(more…)

UISpec, des tests pour iPhone

Tuesday, December 21st, 2010

Mise en place de UISpec sur une application native iPhone.

iPhone et tests fonctionnels ne font pas bon ménage…

Le 6 mars 2008, Apple ouvre l’iPhone à la communauté des développeurs et présente un SDK destiné aux professionnels et aux particuliers. Nous connaissons aujourd’hui le succès de cette ouverture et nous pouvons trouver sur l’Apple Store plus de 250.000 applications. Pourtant, il faut croire que la communauté de développeurs ne s’est guère penchée sur un aspect qui nous est cher à Valtech : l’automatisation des tests fonctionnels, notamment dans le cadre d’une approche de spécification par les tests (TDR, BDD, ATDD).

Alors oui, il y a la possibilité de faire des tests unitaires et du Test Driven Development avec le framework OCUnit qui a été intégré dans le SDK avec la version 2.1 ; mais en ce qui concerne les tests fonctionnels, c’est le désert aride ! Jusqu’à l’arrivée de UISpec, le seul et unique outil à ce jour pour automatiser les tests fonctionnels par l’interface graphique de l’iPhone.
Ca tombe bien, nous l’avons testé !

Ouf ! il y a UISpec et en plus ça marche !

UISpec est à la fois un “driver” de test pour application iPhone et un framework de BDD fortement inspiré de RSpec, écrit en Ruby. UISpec s’intègre dans le code source de l’application iPhone au coté des tests unitaires, et exécute les tests d’interface graphique via l’émulateur iPhone intégré avec XCode.

Vous pouvez alors (more…)

Localisation d’une application WP7

Tuesday, December 7th, 2010

I. Silverlight elements

J’ai utilisé MVVM Light Toolkit pour le projet. MVVM est un design pattern qui ressemble beaucoup au MVC, mais qui a été crée à la base pour répondre aux besoins spécifiques du WPF. Les captures d’écran sont donc des captures d’un projet utilisant MVVM, mais la façon de localiser une application windows phone 7 ne changera pas si vous n’utilisez pas ce design pattern. Je n’ai fait des captures que pour la première partie, mais n’hésitez pas à demander si vous avez besoin de ceux qui vont avec les autres parties. J’ai pensé que le code suffirait.

Etape 1 : Créer les fichiers de ressources pour la localisation

Si vous êtes familier avec le développement Silverlight, vous verrez que cette partie est à peu près la même chose que ce que vous connaissez déjà. Commençons avec (more…)

Construire son système de verrouillage sous Windows Phone 7

Wednesday, December 1st, 2010

Il existe sur vos smartphones un moyen de pouvoir bloquer votre écran afin de protéger vos programmes des autres personnes qui gravitent autour de vous (collègues, amis et autres). Sur les téléphones Androïd, vous avez (pour la plupart d’entre vous) un écran bloquant de ce type :

Le but de notre exemple aujourd’hui est donc de montrer que l’on peut avoir nous aussi (je parle ici de la communauté Windows phone 7) un système similaire, c’est-à-dire (more…)

Tutoriel Spring Roo

Thursday, September 23rd, 2010

Spring Roo est le petit nouveau de la famille Spring Source comprenant déjà Spring et Grails. Tout comme ses ainés,  il s’agit d’un Framework web destiné au développement rapide d’application. Il est « fullstack », c’est à dire englobant l’ensemble des fonctionnalités de la persistance à la présentation.

(more…)

Web sémantique pour la gestion des exigences agiles

Sunday, November 29th, 2009
Qu’est-ce que le web sémantique ?

Dans le web “des humains”, deux pages peuvent être liées entre elles mais le sens de ce lien n’est pas strictement définit par l’auteur de la page.


Le modèle de liens du web.

Dans le web sémantique, le modèle de liens entre pages est enrichi d’une signification connue et non ambiguë.


Modèle de liens du web sémantique.

C’est cet apport d’une signification forte qui forme le triplet “sujet-prédicat-objet”. Rien n’empêche alors de bénéficier de la puissance de calcul des machines pour nous aider à organiser les données.
Par exemple, vous pouvez visiter dbpedia qui est la version sémantique de wikipedia. Exemple: Valtech.

D’où vient la gestion d’exigences ?

La gestion des exigences -dans le cycle de développement logiciel traditionnel en V- est une discipline à part entière qui intervient dans les phases amont du développement. Dans cet univers où la prédictibilité est indispensable, la gestion d’exigences permet de mettre d’accord fournisseur et client sur le contour fonctionnel du système à développer.
Il existe de nombreux outils spécialisés dans cette tâche (Requisite PRO, Doors, etc.). Ils sont portés par des éditeurs de solutions qui ont répondu à un besoin existant dans l’industrie du développement logiciel. A mesure que les échecs des projets ont fait souffrir les clients qui n’obtenaient pas le produit souhaité dans les délais et le budget prévu, la tentation a été de renforcer toujours plus les exigences afin d’établir des contrats encore plus robustes aux aléas de la réalité des projets.

L’approche agile s’inscrit à contre-pied de cette vision en mettant plutôt en avant la collaboration entre le client et le fournisseur plutôt que renforcer leurs positions défensives. De même, je trouve plus pragmatique d’exprimer les exigences aux travers de user stories car cela met les besoins en rapport avec leur utilité pour l’utilisateur. J’ai parfois lu des exigences en ayant l’impression qu’elles étaient “tombées du ciel”, détachées de tout lien avec un scénario utilisateur. J’ai alors eu peur de me perdre en abstractions ce qui peut renforcer la tendance à la sur spécification et au sur développement.

Mais alors, quels outils utiliser pour porter cette relation plus saine ? Comment gérer efficacement les user stories ? Doit-on cesser de spécifier les fonctionnalités et prier pour que le logiciel réalise ce qu’on avait imaginé ? (Bien sûr que non)

Mettre en accord gestion d’exigences et agilité

Dans un projet récent, nous avons utilisé un wiki (MediaWiki, le même produit que celui qui donne vie à Wikipedia) pour faciliter la collaboration. Nous avons ajouté son extension sémantique (Semantic Mediawiki) pour donner encore plus de sens aux informations de spécification.
Un système de gestion d’exigences offre un modèle prédéfinit (parfois extensible) : liste d’exigences, gestion de leur version, génération documentaire, analyse d’impacts, traçabilité. Un wiki sémantique propose quant à lui de définir une “ontologie” (un modèle de données sémantique) au fil des besoins.


Les concepts utilisés dans notre wiki pour
décrire les liens d’une user story.

Le schéma est entièrement adaptable aux informations dans la mesure où lorsqu’un prédicat manque, il suffit simplement de créer un nouveau lien “à la wiki” préfixé par ce prédicat.

La définition progressive du modèle de données est intéressante mais n’est pas utile si on ne sait pas l’exploiter de façon intuitive et simple. Que propose Semantic MediaWiki ?

  • possibilité de définir des requêtes :
    exemple: la liste des user stories avec les acteurs impliqués.
  • navigateur sémantique :
    permet de parcourir l’information en passant par les liens sémantiques qui ont été posés (on dit poser une annotation).

Exemple de User Story dans un wiki sémantique

A quoi ressemble la création d’une user story dans un tel système ? Cela revient à créer une page qui contient des liens sémantiques en utilisant les concepts que l’on s’est donné pour décrire l’information [1].
[[user_story::User Story 8]] of the [[product::WhiteHouse]]
'As a' [[role::PresidentOfTheUnitedStates]]
'I want to' contact any president in the world very fast
'So that' I can defuse any potential international crisis.
Acceptance:
- enter in the White House,
- Simulate an attack on a United State allied country
- Verify that the president can call the president of the attackers immediately
Design Notes:
- [[story_point::8]]
- Set-up a "red phone" with all other country
- [[requires::user Story 6]], [[requires::user Story 12]]
Implementation Notes:
- Use secure lines between capitals.
Following:
- status [[status::IN PROGRESS]]


Les relations sémantiques de la user-story.

Le lien requires permet de représenter les dépendances entre stories.

Exemple de requête

{{#ask: mainlabel=User Story
| [[product::WhiteHouse]]
| ?role=Role
| ?story-point=Estimate
| ?status=Status
| ?requires=Dependencies
| Sort=story-point,role
}}

C’est une requête en ligne donnant le tableau des user stories du produit ‘WhiteHouse’ ordonnées par story point puis rôle.
Il est également possible d’exporter la base sémantique au format RDF pour être exploitée par d’autres outils sémantiques standardisés.

Conclusion

Pour résumer, on arrive à tirer des bénéfices non négligeables d’un tel outil :

  • flexibilité de la base ontologique, adaptation aux besoins
  • capacités de requêtage de l’information
  • édition collaborative

Dans le cas où on utilise la méthode TDR, les solutions actuelles utilisent déjà un wiki pour décrire les cas de tests fonctionnels automatisés. L’ajout de capacités sémantiques permettrait de décupler la valeur descriptive des stories en complément des spécifications exécutables. En particulier, on pourrait ainsi s’éviter de créer manuellement un index des tests en prévenant le risque d’en oublier.


[1]: il est très important que la sémantique utilisée pour décrire les liens soit définie et non ambigüe. On dispose dans ce cas de catalogues de concepts (comme le Dublin Core pour les choses élémentaires, le FOAF pour les relations entre personnes ou d’autres catalogues spécialisés par métier) afin de s’assurer que l’exploitation des informations sera conforme au vocabulaire utilisé.

Tutoriel Android : Mise en place de l’environnement de développement Android 1.6r1 Eclipse Galileo (3.5)

Thursday, October 22nd, 2009

Ce tutoriel a pour objectifs de mettre en place un environnement de développement Android 1.6 sous Eclipse.
A la fin de ce tutoriel vous saurez :

  • Mettre en place Eclipse 3.5 avec le plugin Android
  • Créer une application Android
  • Déployer une application Android dans l’émulateur de votre choix

Installer Eclipse Galileo

Rien de plus simple, il suffit de le télécharger à http://www.eclipse.org/downloads/ et de choisir la version “Eclipse IDE for Java EE Developers” pour votre système d’exploitation.
Une fois téléchargé, pour l’installer il vous suffit de le dézipper !

Installer Android SDK 1.6r1

Commencez par vous rendre à l’url : http://developer.android.com/sdk/ et choisissez la version correspondant à votre plateforme.
Pour l’installer, c’est comme Eclipse, il suffit de dézipper l’archive dans le répertoire de votre choix; dans le cadre de ce tutoriel, j’appellerai ce répertoire $ANDROID_HOME_DIRECTORY.

Astuce : pour avoir accès aux outils Android dans votre “Path” (variables d’environnement), vous pouvez ajouter le répertoire $ANDROID_HOME_DIRECTORY/tools à votre Path. Sous Windows : dans les propriétés de l’ordinateur(raccourci : Windows+Pause ou clique droit sur le poste de travail -> propriétés) cliquez sur l’onglet “Avancé”, de là, sélectionnez “Variables d’environnement” et ajoutez votre chemin d’installation $ANDROID_HOME_DIRECTORY/tools à votre path.
Vous pourrez ainsi avoir accès aux outils android dans toute fenêtre de commande.
Pour tester, ouvrez une fenêtre de commande : Démarrez -> Executer->cmd, et tapez adb, vous devriez avoir ceci :

C:\Documents and Settings\anthony.dahanne&gt;adb
Android Debug Bridge version 1.0.20
 
-d - directs command to the only connected USB device
returns an error if more than one USB device is present.
-e - directs command to the only running emulator.
returns an error if more than one emulator is running.
-s - directs command to the USB device or emulator with
the given serial number
-p - simple product name like 'sooner', or
a relative/absolute path to a product
out directory like 'out/target/product/sooner'.
If -p is not specified, the ANDROID_PRODUCT_OUT
environment variable is used, which must
be an absolute path.
devices - list all connected devices

Si vous ne voulez pas / pouvez pas mettre à jour votre chemin, vous pourrez toujours accéder à l’outil adb par exemple en tapant dans la fenêtre de commande : $ANDROID_HOME_DIRECTORY/tools/adb (en remplaçant ADB_HOME_DIRECTORY par votre répertoire d’installation du SDK Android)

Installation du plugin Eclipse Android SDK

Démarrez Eclipse, et créez un nouveau workspace en choisissant un répertoire au choix (le workspace contiendra tous vos projets)
Juste après, rendez vous dans “Help->Install new software…”
Cliquez sur “Add new site” pour ajouter le site du plugin Android : choisissez le nom que vous souhaitez, et l’url suivante : https://dl-ssl.google.com/android/eclipse/

Ceci étant fait, sélectionnez les 2 cases : DDMS et android tools for eclipse, cliquez sur next, acceptez la licence et c’est fini !

Ecllipse vous demande de redémarrer, acceptez, et au redémarrage d’Eclipse configurez votre plugin Android en allant dans Window->Preferences->Android, de là indiquez votre $ANDROID_HOME_DIRECTORY
Vous pouvez maintenant créez un nouveau projet Android 1.6

Astuce : si vous utilisez eclipse galileo derrière un proxy, vous serez confrontés à des problèmes de connexion, pour les résoudre, consulter : http://blog.dahanne.net/2009/07/01/eclipse-galileo-3-5-problemes_proxy/
Astuce : si vous préférez, vous pouvez télécharger le plugin sans passer par le “Update Manager d’Eclipse”, dans ce cas là, décompresser à la racine de votre instalaltion d’Eclipse le’archive suivante : http://dl.google.com/android/ADT-0.9.3.zip

Au redémarrage d’Eclipse, il vous sera demandé de configurer Eclipse pour qu’il sache où se trouve le SDK Android :

Pour cela, vous devez vous rendre dans Window->Preferences->Android et indiquer le répertoire de votre SDK
C’est bon, vous êtes prêt pour créer votre premier projet Android !

Création de votre premier projet HelloAndroid

Nous allons pour cela utiliser le plugin eclipse Android.
Cliquez sur File->New->Android Project (ou alors File->New->Project et sélectionner Android Project)
Rentrez les informations de votre projet, en particulier, choisissez la version 1.6 de l’API (la plus récente à ce jour, Donut); cependant, sachez que tous les possesseurs de téléphone Android n’ont pas encore mis à jour vers Donut, vous pouvez alors choisir la version 1.5 (Cupcake) pour un maximum de compatibilité

Astuce : vous aurez sans doute remarquer la présence de 2 autres options : Google APIs; ces versions, embarquent, en plus des librairies standards d’Android, les APIs des produits propriétaires Google, comme, par exemple, l’API Maps (si vous voulez afficher une carte Google Maps dans votre application, vous devrez donc choisir Google Api)

Cliquez sur “Finish”, le plugin vous génère alors votre projet, dans mon cas HelloAndroid
Nous allons commencer par observer la classe HelloAndroid.java, qui constitue l’unique activité (considérez pour l’instant qu’il s’agit d’un écran; est une activité une classe qui hérite de Activity) de votre projet :

package com.valtech.helloandroid;
 
import android.app.Activity;
import android.os.Bundle;
 
public class HelloAndroid extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Astuce : vous vous rendrez compte, en suivant la classe Activity avec ctrl+click que vous n’avez pas accès au code source des classes Android.
Or le projet est open source, il serait dommage de se passer d’une telle aide !
Pour voir le code source sous eclipse, telechargez ce fichier zip : http://rgruet.free.fr/public/android-1.5-cupcake-src.zip (il contient les sources d’Android 1.5) et renommez le en sources (sans suffixe de nom de fichiers)
Ensuite, copiez le dans $ANDROID_HOME_DIRECTORY/platforms/android-1.5

Et c’est fini ! Essayer donc un ctrl+click dans Eclipse sur n’importe quelle classe du framework Android, et vous verrez le code source ! (après éventuellement un redémarrage d’Eclipse)

Idem pour la version 1.6, vous pouvez télécharger les sources de cet emplacement : http://rgruet.free.fr/public/android-1.6_r1-donut-src.zip (à renommez en sources dans $ANDROID_HOME_DIRECTORY/platforms/android-1.6)

Le code de HelloAndroid.java stipule qu’à la création de l’activité, on va définir son contenu avec la mise en page (layout) main.

Astuce : R.layout.main est défini dans une classe générée, R qui se présente (pour le moment) ainsi :

public final class R {
public static final class attr {
}
public static final class drawable {
public static final int icon=0x7f020000;
}
public static final class layout {
public static final int main=0x7f030000;
}
}

Toutes les valeurs définies dans ce fichier représentent des ressources, souvent définies sous la forme de fichiers XML (ainsi la valeur main correspond à main.xml dans le dossier res/layout)
Pourquoi est ce fait ainsi ? car les ressources sont traduites en code compilé, ce qui optimise l’empreinte mémoire de vos applications.

Le layout (mise en page) de votre activité est donc définie dans res/layout/main.xml :

Je vous laisse retrouver la valeur de @string/hello dans les ressources !
On voit ici que un TextView (un label) a été défini, ainsi, lors du déploiement de HelloAndroid, on devrait s’attendre à voir un écran avec un label

D’ailleurs pour que cette activité soit activée, elle doit être référencée dans le manifest de votre projet : AndroidManifest.xml

Vous l’avez compris, le manifest est le fichier le plus important de votre projet : il référence toutes vos activités (et bien plus !)
Nous pouvons maintenant passer au déploiement du projet dans un émulateur.

Déploiement de votre projet Android

Votre projet peut être déployé sur un téléphone équipé d’Android, ou sur un émulateur.
Pour celà, cliquez droit sur votre projet et sélectionnez “Run as Android Application.”

Comme il s’agit de votre premier déploiement, le plugin Android vous propose de créer une nouvelle instance d’émulateur: un AVD (Android Virtual Device) :

Une fois votre AVD paramétrée, cliquez sur “Create Avd”, votre AVD est créée, vous pouvez alors la sélectionner pour déployer votre projet sur cette dernière ! (après éventuellement avoir fait un “Refresh”)

Astuce : il n’est pas nécessaire de redémarrer votre AVD à chaque modification de votre projet !En cliquant sur Run as Android application, votre projet se re déploiera dans votre AVD existante.

Astuce : pour changer l’orientation de votre AVD , composez Ctrl+F11
Astuce : il existe plusieurs “skins” pour votre AVD : en effet, si vous souhaitez créer votre AVD avec une skin différente, par exemple celle proposée par Archos pour leur futurs tablet pc android, vous pouvez télécharger la skin : http://appslib.com/download/a5_horiz.zip, la dézipper dans $ANDROID_HOME_DIRECTORY/platforms/android-1.5/skins

En redémarrant Eclipse, et en cliquant sur l’icone du téléphone, vous pourrez créer une nouvelle AVD qui correspondra à une cible Android avec une plus haute résolution que celle d’un téléphone: idéal pour tester vos applications sur plusieurs cibles différentes !
Pour modifier votre configuration de lancement, allez dans Run-> Run configurations …, et sous l’onglet Target de votre projet, vous pourrez choisir quelle sera l’émulateur à lancer par défaut !

Astuce : vous pouvez aussi renseigner d’autres options à votre émulateur, comme la vitesse du CPU, un éventuel proxy à lui préciser , etc… dans le champ “Additionnal Emulator Command Line Options”, toutes les options sont sur http://developer.android.com/guide/developing/tools/emulator.html
Astuce : si votre projet Android est défini comme étant un projet android 1.6, il faut le déployer dans un AVD (émulateur) version 1.6 ! (un projet Android 1.5 se déploie aussi bien dans un AVD 1.5 que 1.6)

Félicitations ! Votre premier projet, HelloAndroid, est déployé dans votre émulateur !

Références :

Maveniser l’intégration de Flex, Spring et BlazeDS

Thursday, August 20th, 2009

Ce tutoriel présente l’implémentation d’une application Flex consommant des services Java exposés via le framework BlazeDS.

Les particularités de ce tutoriel, par rapport à ceux que l’on peut trouver sur Internet, portent sur:

  • l’industrialisation avec Maven, pour un développement professionnel
  • l’intégration de Spring-Flex, pour simplifier la configuration de BlazeDS

Les sources sont disponibles et facilement compilables (voir les pré-requis et les instructions de compilation et de déploiement).

valtechflexblazedstuto-20100330.zip

I) Introduction

1) Flex

Flex est un framework Open Source dédié à au développement d’applications web de type RIA. Créée à l’origine par Macromedia en 2004, cette technologie a été reprise par Adobe en 2006.

Les applications développées en Flex s’exécutent indifféremment dans un navigateur web muni du module Adobe Flash® Player ou en local via le moteur d’exécution Adobe AIR™.

Son modèle de programmation s’appuie sur un langage déclaratif basé sur XML, le MXML, et sur un langage de script orienté objet, l’ActionScript. Le premier permet de décrire l’apparence et le comportement de l’interface utilisateur, le deuxième permet d’implémenter les traitements coté client.

Bien qu’il soit possible de développer en se limitant à l’utilisation du Flex SDK, vos développements seront nettement plus productifs s’ils s’appuient sur l’environnement dédié et commercialisé par Adobe sous le nom de « Flex Builder ». Basé sur Eclipse, cet IDE est distribué sous une forme packagée ou sous forme de plugin.

Parfaitement adapté à la création d’IHM riches et érgonomiques, Flex l’est beaucoup moins pour implémenter le code métier d’une application d’entreprise où les technologies telles que java ou .Net règnent en maitres absolus. De ce fait, une application Flex qui souhaite manipuler des données stockées en base doit de communiquer avec un composant de type serveur. Bien que Flex permette de consommer des services déployées sous la forme de services web de type SOAP ou REST, Adobe propose une autre solution technique élégante et bien plus productive.

2) BlazeDS

BlazeDs est un framework permettant de connecter une application cliente Flex à une application serveur Java.

Les principes mis en oeuvre sont relativement simples. Un client Flex envoie des requêtes à destination d’un serveur BlazeDS via un ‘canal’ (channel) dédié. Ces requêtes sont interceptées par une servlet fournie par BlazeDS (MessageBrokerServlet) puis traitée par un Adapter. Il existe plusieurs types d’Adapters, celui utilisé dans ce tutoriel permet d’exécuter des services implémentés sous forme de simples POJO (JavaAdapter), d’autres, tel que le JMSAdapter, permet de reléguer le traitement à un serveur distant via le protocole JMS.

La documentation officielle explique ceci en détail: http://livedocs.adobe.com/blazeds/1/blazeds_devguide/help.html?content=Part_ChannelsEndpoints_1.html.

II) Mise en œuvre

Il existe aujourd’hui deux solutions pour mettre en œuvre un projet Flex/Java/BlazeDS.
La plus rapide mais aussi la moins maintenable consiste à créer, directement dans l’environnement FlexBuilder, un projet regroupant l’application Flex, le code Java et la web application.
La 2ème solution, préconisée dans ce tutoriel, consiste à créer un projet Maven regroupant deux modules: un pour l’application Flex et un pour l’application web.

La première solution a été abordée dans différents articles sur le net et reste conseillée dans une optique de mise en œuvre rapide de POC (Proof Of Concept). La deuxième solution, totalement industrialisée (compilation, packaging et déploiement orchestrés par Maven et intégrée en continu) est clairement destinée à un développement professionnel.

La solution proposée permettrait presque de se passer de FlexBuilder. “Presque” car la plus value apportée par FlexBuilder en termes de développement et de debugging reste incontournable. Incontournable, certes, mais qui nécessite une double configuration: dans FlexBuilder et dans Maven.

1) Pré-requis

Ce tutoriel a été développé avec le JDK6, Maven 2.1.0, FlexBuilder3 sous Eclipse Ganymede (3.4) et Tomcat 6.0.20.

Pour faire fonctionner le tout, il faut au préalable avoir installé sur sa machine de développement les composants suivants:

Les sources de ce tutoriel se veulent les plus simples possibles afin d’êtres facilement réutilisables.

Pour éditer les sources, il suffit d’importer, depuis Eclipse/FlexBuilder, les différents projets en spécifiant le répertoire racine du projet valtechFlexBlazeDsTut.

2) Intégration avec Maven

Il y a encore quelques mois, aucun ‘repository’ Maven public n’hébergeait les archives nécessaires à la compilation de projets Flex. Heureusement, la société Sonatype a fait un gros travail et a mis à disposition tout ce qui est nécessaire à la construction d’une application Flex avec Maven. Le fichier de configuration Maven (settings.xml), livré avec les sources de ce tutoriel, doit être copié dans votre répértoire de settings C:\Documents and Settings\monNom\.m2\.
Dans le cas où vous disposeriez déjà d’un tel fichier, la modification à apporter porte sur sur la déclaration de ce nouveau dépot:
Note: Voir aussi le lien donné par VELO (commentaire en fin de page) sur la déclaration du repository: https://docs.sonatype.org/display/FLEXMOJOS/Referencing+Flexmojos+maven+repository

<...>
            <repository>
                <id>sonatype</id>
                <url>http://repository.sonatype.org/content/groups/flexgroup</url>
                <releases><enabled>true</enabled></releases>
                <snapshots><enabled>false</enabled></snapshots>
            </repository>
<...>

La ‘mavenisation’ de notre projet consiste à créer un projet multi-modules composé au minimum de l’application Flex et de l’application web exposant les services Java.
La première difficulté rencontrée concerne la mise en commun des fichiers de configuration permettant de lier les deux mondes Flex et Java. Pour éviter de copier/coller ces fichiers dans les deux projets, il est possible de créer un module dédié, dit de configuration, dont dépendront les modules Flex et Java.

Un projet parent ordonnancera la construction des différents modules. Voici comment ce projet multi-modules est organisé:

- valtechFlexBlazeDsTuto (le projet parent)
`– pom.xml
`– valtechBlazeDsFlexApp (l’application Flex)
`– valtechBlazeDsResources (les ressources communes à Flex et Java)
`– valtechBlazeDsWebApp (la web-app et les services Java)

3) Le projet parent: valtechFlexBlazeDsTuto

Il s’agit d’un simple projet contenant 3 répertoires, correspondant aux 3 modules, et un fichier pom.xml.

Dans ce pom, on déclare simplement les 3 modules enfants (l’ordre de compilation est important) et les différents plugins que l’on va utiliser.
Pour rappel, le premier module contient les fichiers de configuration de BlazeDs, le 2ème module contient l’application Flex et enfin le 3ème module contient la web-app et les services java.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>fr.valtech.flex</groupId>
    <artifactId>valtechFlexBlazeDsTuto</artifactId>
    <packaging>pom</packaging>
    <version>1.0</version>
    <name>valtechFlexBlazeDsTuto</name>
    <url>http://www.valtech.fr</url>
 
    <!-- les propriétés réutilisées dans les poms des différents projets-->
    <properties>
        <compileSource>1.6</compileSource>    
    </properties>
 
    <!-- les 3 modules, dans l'ordre de compilation-->
    <modules>
        <module>valtechBlazeDsResources</module>
        <module>valtechBlazeDsFlexApp</module>
        <module>valtechBlazeDsWebApp</module>
    </modules>
 
    <build>
        <pluginManagement>
            <plugins>
                <!-- le plugin pour gérer les dépendances, dans notre cas des ressources
                     vers les projets Flex et Java-->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-dependency-plugin</artifactId>
                    <version>2.0</version>
                    <configuration>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <!-- le plugin qui nous permettra de créer le zip contenant les
                     ressources communes aux projets Flex et Java-->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <version>2.2-beta-4</version>
                    <configuration>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>            
            <plugin>
                <!-- Pour spécifier à maven de compiler les sources en
                    autre chose que java 1.3 :) -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${compileSource}</source>
                    <target>${compileSource}</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
 
        </plugins>
    </build>
 
    <developers>
        <developer>
            <id>jbcazaux</id>
            <name>Jean-Baptiste Cazaux</name>
            <email>jean-baptiste.cazaux@valtech.fr</email>
            <organization>Valtech</organization>
            <organizationUrl>http://www.valtech.fr</organizationUrl>
        </developer>
    </developers>
 
</project>

3) Le projet de configuration: valtechFlexBlazeDsResources

Ce module contient les 2 fichiers nécessaires au bon fonctionnement de BlazeDS. L’objectif de ce module est de générer une archive au format zip contenant ces fichiers. Cette archive sera installée dans le repository Maven puis automatiquement recopiée, lors de la compilation, dans les 2 projets Flex et Java.

- valtechBlazeDsResources
`– pom.xml
`– src
`– assembly
`– resources.xml
`– resources
`– remoting-config.xml
`– services-config.xml

Les fichiers de configuration servent principalement à décrire les canaux d’échange des requêtes entre le client Flex et la web-app contenant les services Java.

a) resources.xml

Ce fichier permet de configurer le plugin Maven en charge de génèrer le zip. Il sera donc référencé dans le pom.xml.

<assembly>
    <id>resources</id>
    <formats>
        <!-- Nous voulons créer un zip au final -->
        <format>zip</format>
    </formats>
    <!-- Pour ne pas inclure le chemin complet du répertoire de base des fichiers de configuration-->
    <includeBaseDirectory>false</includeBaseDirectory>
    <fileSets>
        <fileSet>
            <!-- le répertoire où sont stockés les fichiers de configuration BlazeDS -->
            <directory>src/resources/</directory>
            <!-- chemin du répertoire dans le zip et qui contiendra les fichier blazeDS, ici vide-->
            <outputDirectory></outputDirectory>
        </fileSet>
    </fileSets>
</assembly>
b) pom.xml

Rien de spécial dans ce pom, si ce n’est l’utilisation du plugin “assembly” permettant de générer le fichier zip lors du lancement de la commande mvn:package

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <!-- Le projet parent-->
    <parent>
        <groupId>fr.valtech.flex</groupId>
        <artifactId>valtechFlexBlazeDsTuto</artifactId>
        <version>1.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>fr.valtech.flex</groupId>
    <artifactId>valtechBlazeDsResources</artifactId>
    <version>1.0</version>
    <packaging>pom</packaging>
    <name>valtechBlazeDsResources</name>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.2-beta-4</version>
                <executions>
                    <execution>
                        <id>make shared resources</id>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <phase>package</phase>
                        <configuration>
                            <descriptors>
                                <!-- référence vers le fichier resources.xml
                                     que nous venons de voir-->
                                <descriptor>src/assembly/resources.xml</descriptor>
                            </descriptors>
                            <encoding>UTF-8</encoding>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
c) services-config.xml

C’est le fichier qui permet de configurer les canaux sur les quels communiquent les applications Flex et Java. Il fait référence à un deuxième fichier que nous verrons juste après.

Dans le cadre du tutoriel, nous utilisons un seul canal de type “AMFChannel”. Ce type de canal permet l’échange de message au format AMF (Action Message Format), format propriétaire mais optimisé.

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
 
    <services>
        <service-include file-path="remoting-config.xml" />
 
        <!-- le canal amf par défaut -->
        <default-channels>
           <channel ref="valtech-amf"/>
        </default-channels>
    </services>
 
    <channels>
 
        <!-- définition des canaux amf, ici un canal standard (non sécurisé, non crypté) -->
        <channel-definition id="valtech-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>
 
 
    <!-- Pour logger les messages AMF qui passent, indiquer level="Debug" -->
    <logging>   
 
        <target class="flex.messaging.log.ConsoleTarget" level="Error">
            <properties>
                <prefix>[BlazeDS] </prefix>
                <includeDate>false</includeDate>
                <includeTime>false</includeTime>
                <includeLevel>false</includeLevel>
                <includeCategory>false</includeCategory>
            </properties>
            <filters>
                <pattern>Endpoint.*</pattern>
                <pattern>Service.*</pattern>
                <pattern>Configuration</pattern>
            </filters>
        </target>
    </logging>
 
    <system>
        <redeploy>
            <enabled>false</enabled>
        </redeploy>
    </system>
 
</services-config>
d) remoting-config.xml

C’est dans ce fichier que l’on déclare interagir avec du code java.

<?xml version="1.0" encoding="UTF-8"?>
 
<service id="remoting-service"
    class="flex.messaging.services.RemotingService">
 
    <adapters>
        <!-- on demande a BlazeDs d'interagir avec du code java -->
        <adapter-definition id="java-object"
          class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/>
    </adapters>
 
    <default-channels>
        <!-- canal utilisé par défaut pour discuter, ce canal avait été déclaré
             dans services-config.xml  -->
        <channel ref="valtech-amf"/>
    </default-channels>     
</service>

3) L’application Flex: valtechBlazeDsFlexApp

L’application est volontairement simple. Elle se limite à la consommation d’un service dont la signature déclare en entrée comme en sortie une chaine de caractère.

Le service Java prend un nom en entrée et retourne un message de bienvenue concaténé au nom passé en paramètre.

L’interface propose donc un champ dédié à la saisie du nom de l’utilsateur, un bouton pour déclencher l’appel au service et un champ pour en afficher le resultat.

Le module se compose des sources flex et du pom utilisé pour la compilation du projet. L’utilisation de FlexBuilder permet de génèrer les sources HTML nécessaire au lancement l’application dans un navigateur. Cette fonctionnalité nous évite ainsi de produire à la main du code HTML pas spécialement intéressant. Je ne détaillerai pas non plus les autres fichiers générés par FlexBuilder, comme les fichiers .actionScriptProperties et .flexProperties, utilisés pour conserver les paramètres de compilation (de FlexBuilder, pas ceux de maven !).

- valtechBlazeDsFlexApp
`– pom.xml
`– src
`– main
`– flex
`– flexApp.mxml

a) flexApp.mxml

Il s’agit du fichier principal de l’application Flex.

Dans ce fichier apparaissent une description de l’interface minimaliste de l’application, la déclaration du service distant et son appel.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" width="451" height="168"
    paddingBottom="0" paddingLeft="0" paddingRight="0" paddingTop="0">
 
    <mx:Script>
        <![CDATA[
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
 
            /**
             * Méthode appelée lors du clic sur le bouton d'envoie
             */
            private function doCall():void{
                // Appeler le service distant
                roWelcomeService.sayHello(tiLogin.text);
            }
 
            /**
             * Méthode invoquée en cas de succès de l'appel RPC
             */
            private function onResult(event : ResultEvent):void{
                // Afficher la réponse dans le textArea
                taReponse.text = event.result as String;
            }
 
            /**
             * Méthode invoquée en cas d'échec de l'appel RPC
             */
            private function onFault(event : FaultEvent):void{
                // Afficher le message d'erreur dans le textArea
                taReponse.text = event.fault.message;
            }
 
        ]]>
    </mx:Script>
 
    <!--  déclaration du remoteObject qui sait faire des appels distants -->
    <!--  la destination correspond au nom donné dans le fichier remoting-config.xml -->
    <!--  On déclare également 2 methodes de callback, qui seront appelées en cas de réussite ou -->
    <!--  d'échec de l'appel au service -->
    <mx:RemoteObject id="roWelcomeService"
                     destination="welcomeServiceDest"
                     result="onResult(event)"
                     fault="onFault(event)"/>
 
    <!-- interface graphique minimaliste -->
 
    <mx:Panel width="451" height="168" layout="absolute" title="Hello World maven">
        <mx:Label x="10" y="10" text="Login : "/>
        <mx:TextInput id="tiLogin" text="Guest"
                      x="66" y="8" />
        <mx:Button id="btnAppel" label="Appel de WelcomeService"
                   x="234" y="8"
                   click="doCall()"/>
        <mx:Label x="10" y="38" text="Réponse :"/>
        <mx:TextArea id="taReponse"
                     x="81" y="37" width="327" height="81"/>
    </mx:Panel>
 
</mx:Application>
b) pom.xml

Le pom du projet Flex a deux principaux rôles. Tout d’abord, il permet de configurer la phase de compilation. La liste des options de compilation, comme celles permettant de spécifier des locales par exemple, est consultable à l’adresse suivante: http://www.sonatype.com/books/maven-book/reference/flex-dev-sect-compiling.html. Le 2ème est la copie des fichiers de configuration BlazeDS que nous avions zippés dans le projet valtechFlexBlazeDsResources.

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <!-- Le projet parent-->
    <parent>
        <groupId>fr.valtech.flex</groupId>
        <artifactId>valtechFlexBlazeDsTuto</artifactId>
        <version>1.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <groupId>fr.valtech.flex</groupId>
    <artifactId>flexClient</artifactId>
    <version>1.0</version>
    <!-- Il faut indiquer que nous voulons un swf en sortie (on peut aussi générer des swc) -->
    <packaging>swf</packaging>
    <name>Flex client</name>
    <build>
        <sourceDirectory>src/main/flex</sourceDirectory>
        <testSourceDirectory>src/test/flex</testSourceDirectory>
        <plugins>
            <plugin>
                <!-- le plugin dependency qui va nous permettre de dézipper
                    les fichiers de configuration là où l'on le souhaite-->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>unpack-shared-resources</id>
                        <goals>
                            <goal>unpack-dependencies</goal>
                        </goals>
                        <phase>generate-resources</phase>
                        <configuration>
                            <!-- on dézippe dans le répertoire target/generated-resources -->
                            <outputDirectory>
                              ${project.build.directory}/generated-resources
                            </outputDirectory>
                            <!-- il faut indiquer le nom de l'artefact à dézipper -->
                            <includeArtifactIds>valtechBlazeDsResources</includeArtifactIds>
                            <excludeTransitive>true</excludeTransitive>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <!-- le plugin de sonatype pour compiler les projets flex -->
                <groupId>org.sonatype.flexmojos</groupId>
                <artifactId>flexmojos-maven-plugin</artifactId>
                <version>3.2.0</version>
                <extensions>true</extensions>
                <configuration>
                    <!-- il faut indiquer où est le fichier services-config.xml -->
                    <services>
                      ${project.build.directory}/generated-resources/flex/services-config.xml
                    </services>
                    <!-- url context de l'application java (web-app) qui sera appelée-->
                    <contextRoot>valtechFlexDemo</contextRoot>
                </configuration>
            </plugin>
 
        </plugins>
    </build>
 
    <dependencies>
 
        <!-- la dépendance vers les fichiers de configuration BlazeDs.
             Ne pas oublier de stipuler le format (type) -->
        <dependency>
            <groupId>fr.valtech.flex</groupId>
            <artifactId>valtechBlazeDsResources</artifactId>
            <version>1.0</version>
            <classifier>resources</classifier>
            <type>zip</type>
            <scope>provided</scope>
        </dependency>
 
        <dependency>
            <groupId>com.adobe.flex.framework</groupId>
            <artifactId>flex-framework</artifactId>
            <version>3.3.0.4852</version>
            <type>pom</type>
        </dependency>
 
        <!-- Si jamais il y a des Test Unitaires dans votre application flex...-->
        <dependency>
            <groupId>org.sonatype.flexmojos</groupId>
            <artifactId>flexmojos-unittest-support</artifactId>
            <version>3.2.0</version>
            <type>swc</type>
            <scope>test</scope>
        </dependency>
    </dependencies>
 
</project>

4) La web application: valtechBlazeDsWebApp

Ce projet représente l’application dans son ensemble. Il est composé des sources java des services exposés à l’applicaiton Flex, des fichiers de configuration de Spring (un pour gérer les beans, un autre pour configurer BlazeDS) et des sources de l’application web (le fichier web.xml, les fichiers html et autres fichiers javascript).

On utilisera de nouveau le plugin dependency pour copier les 2 fichiers de configuration BlazeDS (issus de l’archive zippée) et le fichier swf.

La déclaration des services java disponibles par l’application Flex se fait grâce à l’annotation @RemotingDestination fournie par le projet Spring BlazeDS integration, livré sous forme de jar.

- valtechBlazeDsWebApp
`– pom.xml
`– src
`– main
`– java
`– com.valtech
`– service
`– WelcomeService.java (le service exposé)
`– resources
`– applicationContext.xml (le fichier de configuration de Spring)
`– webapp
`– WEB-INF
`– web.xml (le descripteur de déploiement de la webapp)
`– flex-servlet-context.xml (la configuration de Spring-BlazeDS)
`– flexClient.html (la page qui affiche l’application Flex)

a) applicationContext.xml

Le fichier configuration standard de Spring où sont définis les beans managés par Spring.

<?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-2.5.xsd">
 
    <!-- Les déclaration du bean WelcomeService n'est pas présente
           dans ce fichier de configuration car elle s'appuie sur les annotations) -->
 
</beans>
b) L’implémentation du service: WelcomeService.java

Tout comme le service rendu, l’implémentation du service est minimaliste!

package com.valtech.service;
 
import org.springframework.flex.remoting.RemotingDestination;
import org.springframework.stereotype.Service;
 
//déclare le bean comme étant managé par spring
@Service
// déclare le bean comme étant accessible par Flex
@RemotingDestination(value = "welcomeServiceDest")
public class WelcomeService {
 
    public String sayHello(String pLogin) {
        return "Bienvenue à toi " + pLogin;
    }
}
c) web.xml

Il est nécessaire de déclarer dans le descripteur de déploiement, le fichier de configuration de Spring à charger au démarrage et la servlet Spring qui configure BlazeDS.

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                             http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>simple-form</display-name>
 
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
 
    <context-param>
        <!-- fichier de configuration de spring -->
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
 
    <filter>
        <filter-name>encoding-filter</filter-name>
        <filter-class>
            org.springframework.web.filter.CharacterEncodingFilter
        </filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
 
    <filter-mapping>
        <filter-name>encoding-filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
 
    <!-- configuration de la servlet qui gérera les messages AMF-->
    <servlet>
        <servlet-name>spring-flex</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/flex-servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>spring-flex</servlet-name>
        <url-pattern>/messagebroker/*</url-pattern>
    </servlet-mapping>
 
    <welcome-file-list>
        <welcome-file>flexClient.html</welcome-file>
    </welcome-file-list>
 
</web-app>
d) pom.xml

Mis à part la partie dédiée à la copie des 2 fichiers de ressources et de l’application Flex, ce pom est un classique pom de construction d’applications web.

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 
    <!-- Le projet parent-->
    <parent>
        <groupId>fr.valtech.flex</groupId>
        <artifactId>valtechFlexBlazeDsTuto</artifactId>
        <version>1.0</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
 
    <modelVersion>4.0.0</modelVersion>
    <groupId>fr.valtech.flex</groupId>
    <artifactId>valtechFlexBlazeDsWebApp</artifactId>
    <!-- Nous générons un war -->
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>valtechFlexDemo Webapp</name>
 
    <build>
        <finalName>valtechFlexDemo</finalName>
 
        <resources>
            <!-- Le répertoire où seront copiés les fichiers de configuration de BlazeDs -->
            <resource>
                <directory>${project.build.directory}/generated-resources</directory>
            </resource>
 
            <resource>
                <!-- A partir du moment où l'on ajoute un 2ème répertoire de ressources,
                     il faut redéclarer le répertoire par défaut-->               
                <directory>${basedir}/src/main/resources</directory>
            </resource>
 
 
        </resources>
 
        <plugins>
 
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>unpack-shared-resources</id>
                        <goals>
                            <goal>unpack-dependencies</goal>
                        </goals>
                        <phase>generate-resources</phase>
                        <configuration>
                            <!-- le zip contenant les 2 fichiers de configuration de
                                 BlazeDs sera décompressé dans le répertoire
                                 target/generated-resources qui a été déclaré comme
                                 répertoire de ressources.
                                 C'est exactement le même principe que ce qui avait été fait
                                 dans le projet Flex-->
                            <outputDirectory>
                               ${project.build.directory}/generated-resources
                            </outputDirectory>
                            <includeArtifactIds>valtechBlazeDsResources</includeArtifactIds>
                            <excludeTransitive>true</excludeTransitive>
                        </configuration>
                    </execution>
                    <execution>
                        <id>copy-flex-app</id>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <!-- Cette fois ci, c'est l'application Flex qui est copiée dans la
                                 web-app. On copie le swf dans le répertoire target/generated-flex.
                                 Par la même occasion on renomme le swf en flexClient.swf,
                                 cela évitera de changer le fichier html qui charge le swf -->
                            <artifactItems>
                                <artifactItem>
                                    <groupId>fr.valtech.flex</groupId>
                                    <artifactId>flexClient</artifactId>
                                    <version>1.0</version>
                                    <type>swf</type>
                                    <outputDirectory>
                                      ${project.build.directory}/generated-flex
                                    </outputDirectory>
                                    <destFileName>flexClient.swf</destFileName>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
 
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <!-- Il faut configurer le plugin maven-war pour ajouter un répertoire
                        de ressources supplémentaire, ici le répertoire dans lequel
                        le swf est copié (target/generated-flex) -->
                    <webResources>
                        <resource>
                            <directory>${project.build.directory}/generated-flex</directory>
                        </resource>
                    </webResources>
                </configuration>
            </plugin>
 
        </plugins>
 
    </build>
 
    <dependencies>
        <!-- la dépendance vers le fichier zip qui contient les configurations BlazeDs-->
        <dependency>
            <groupId>fr.valtech.flex</groupId>
            <artifactId>valtechBlazeDsResources</artifactId>
            <version>1.0</version>
            <classifier>resources</classifier>
            <type>zip</type>
            <scope>provided</scope>
        </dependency>
        <!-- la dépendance vers le projet flex-->
        <dependency>
            <groupId>fr.valtech.flex</groupId>
            <artifactId>flexClient</artifactId>
            <version>1.0</version>
            <type>swf</type>
            <scope>provided</scope>
        </dependency>
 
        <!-- les dépendances BlazeDs-->
        <dependency>
            <groupId>com.adobe.flex.compiler</groupId>
            <artifactId>flex-messaging-common</artifactId>
            <version>3.3.0.4852</version>
        </dependency>
 
        <dependency>
            <groupId>com.adobe.blazeds</groupId>
            <artifactId>blazeds-remoting</artifactId>
            <version>3.2.0.3978</version>
        </dependency>
 
        <dependency>
            <groupId>com.adobe.blazeds</groupId>
            <artifactId>blazeds-core</artifactId>
            <version>3.2.0.3978</version>
        </dependency>
 
        <dependency>
            <groupId>com.adobe.blazeds</groupId>
            <artifactId>blazeds-opt</artifactId>
            <version>3.2.0.3978</version>
        </dependency>
 
        <dependency>
            <groupId>com.adobe.blazeds</groupId>
            <artifactId>blazeds-proxy</artifactId>
            <version>3.2.0.3978</version>
        </dependency>
 
        <!-- Les dépendances spring-flex -->       
        <dependency>
          <groupId>org.springframework.flex</groupId>
          <artifactId>spring-flex</artifactId>
          <version>1.0.0.RELEASE</version>
        </dependency>
 
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>${spring.version}</version>
        </dependency>
 
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring</artifactId>
            <version>${spring.version}</version>
        </dependency>
 
        <!-- Les autres dépendences  -->
        <dependency>
          <groupId>xalan</groupId>
          <artifactId>xalan</artifactId>
          <version>2.7.1</version>
        </dependency>
 
    </dependencies>
 
    <properties>
        <spring.version>2.5.6</spring.version>
    </properties>
 
</project>

5) Déploiement

Un simple ‘mvn clean install’ exécuté à la racine du projet valtechFlexBlazeDsTuto devrait suffire pour compiler les sources et générer le war.

Lors de la configuration du serveur d’application, si le contexte de déploiement est demandé, il est important de bien spécifier le contexte indiqué dans le pom.xml de l’application Flex et le web.xml de la web-app (‘valtechFlexDemo‘ dans notre exemple). Par exemple pour tomcat:

  <Context path="/valtechFlexDemo" debug="0" privileged="true" 
      docBase="D:/JBC/valtechFlexBlazeDsTuto/valtechBlazeDsWebApp/target/valtechFlexDemo">
  </Context>

Une fois le serveur démarré, il suffit de lancer un navigateur web et pointer sur l’adresse http://localhost:8080/valtechFlexDemo.

IV) Aller plus loin

L’implémentation de services Java déclarant en entrée et/ou en sortie des objets complexes qui collent plus à la réalité ne devrait pas révolutionner la configuration BlazeDS.

La bonne intégration de BlazeDs et de Spring permet d’associer ‘Spring Security’ très simplement.

Dans un prochain tutoriel, nous aurons l’occasion de créer une application intégrant également les bonnes pratiques de développement telles que la délégation des appels de services ou encore la mise en œuvre du pattern MVC via Flex-MVC (Cairngorm).

V) Références


JB Cazaux, Consultant Valtech Java/JEE. jean-baptiste.cazaux[at]valtech.fr