Les tableaux de bords dans Pentaho avec les C*tools

admin janvier 2nd, 2012

Introduction

Dans une suite décisionnelle, le tableau de bord (ou « dashboard ») est un élément clef pour fournir des informations synthétiques facilement accessibles.

Le pilotage stratégique, le pilotage opérationnel et les indicateurs de performances (KPIs) sont autant de cas d’utilisations des tableaux de bords. La plupart du temps, un dashboard présente un maximum d’informations dans un minimum de place, en faisant appel à une grande interactivité et à de multiples composants graphiques.

Mettre en place des tableaux de bords dans la version libre (Community) de Pentaho n’a pas été toujours une chose très aisée (ce n’est pas le cas de la version Enterprise qui propose un module WYSIWYG full Web à destination des utilisateurs métier).

Dans les premières versions de la plate-forme, les dashboards devaient être codés directement en langage JSP (Java Server Page), ce qui nécessitait une connaissance très avancée des classes Java internes, des libraires graphiques (JFreeChart) et du fonctionnement des séquences d’actions (Xactions).

Très difficile donc (voir impossible) de mettre en place des dashboards sans avoir un profil de développeur JAVA !!

C’est dans ce contexte qu’est né en 2009 le projet communautaire Pentaho CDF (Community Dashboard Framework), à l’initiative de Pedro Alves (de WebDetails)

Son objectif était simple: fournir une API complète permettant de s’affranchir de la complexité interne de Pentaho grâce au paradigme MVC (Modèle-Vue-Contrôleur)

Au fur et mesure, d’autres projets se sont greffés à Pentaho CDF, pour constituer ce qu’on appelle désormais les « C*tools » :

  • CDA (Community Data Access), pour accéder de manière simple et flexible à de multiples sources de données (en SQL, MDX, XML, PDI, Metadata, scripting…). CDA dispose notamment d’un mécanisme de mise en cache et permet d’effectuer des jointures entre des sources hétérogènes par simple configuration XML.
  • CCC (Community Charting Components), une très bonne librairie de visualisation graphique s’appuyant sur Protovis, un projet open source de data-visualization (Javascript+SVG)
  • CST (Community Startup Tabs), un plugin qui permet de paramétrer les onglets à afficher au lancement de la « Pentaho User Console », en fonction des droits de l’utilisateur connecté
  • CDE (Community Dashboard Editor), pour la création et la publication de tableaux de bords directement depuis l’interface web de Pentaho.

Les C*tools permettent de délivrer des tableaux de bord d’une qualité professionnelle, en minimisant la complexité liée à de l’écriture de code. Jetez plutôt un œil sur cette présentation afin d’en prendre pleinement la mesure :

Installation des C*tools

Chacun des C*tools est disponible sous forme de plugin serveur Pentaho, l’installation consiste au dépôt d’un simple dossier dans le répertoire /pentaho-solutions/system

(Note: les C*tools fonctionnent à partir de la version 3.6 de Pentaho)

En raison des dépendances entre les différents plugins, il est vivement conseillé d’utiliser le script d’installation ctools-installer.sh (Linux). Ce script fonctionne également sous Windows à condition d’installer Cygwin (émulateur Linux pour Windows). Retrouvez tous les détails pour effectuer cette installation dans ce post de Pedro Alves.

Exemple de mise en place d’un tableau de bord


1. Principes de base de Pentaho CDE

Pour réaliser un tableau de bord avec Pentaho CDE, il faut avant toute chose avoir une idée assez précise du résultat final !

Cela revient à définir une petite maquette dans laquelle on va spécifier :

  • la structure du dashboard (le « Layout »)
  • les différents composants (« Components ») du dashboard : graphiques, tableaux de données, objets web (listes déroulantes, cases à cocher, calendrier…)
  • les interactions entre les composants, au travers de paramètres (« Parameters »)
  • les sources de données nécessaires à l’alimentation des composants (« Data Sources »)

Prenons un exemple simple de tableau de bord à réaliser :

Ce tableau de bord s’appuie sur les données de la base de démo de Pentaho (SampleData). Il contient un en-tête avec le titre, une zone pour le choix des paramètres (sélection de l’année) ainsi que 2 objets graphiques représentant respectivement le montant total des ventes par zone (Camembert) et le détail des ventes par gamme de produit sur 2 années consécutives (Histogramme)

2. Création du Layout

Dans CDE, l’onglet Layout permet de positionner et d’agencer les différents composants de la page web.

Pentaho CDE repose sur le framework CSS BluePrint qui permet une mise en page simplifiée. Le point le plus important à noter est que ce framework repose sur une grille de 24 colonnes, d’où l’obligation de faire en sorte que la somme des attributs « span » de toutes les colonnes d’une même ligne soit égale à 24.

Notre tableau de bord présente la structure suivante :

La mise en place est illustrée par la vidéo ci-dessous. Notez qu’on peut personnaliser de façon très avancée la mise en forme grâce à l’utilisation de feuilles de styles CSS comme celle ajoutée dans la vidéo (c’est d’ailleurs sans doute ce point qui nécessite le plus de connaissances techniques) :


3. Création des requêtes et affectation aux différents composants

3 requêtes SQL sont à créer pour le tableau de bord, chacune de ces requêtes étant associée à un composant.

La requête « select_year_query » permet d’alimenter les années affichées de la liste déroulante :

SELECT DISTINCT YEAR_ID FROM ORDERFACT

La requête « piechart_query » permet de créer le diagramme en secteur (« Pie Chart ») :

SELECT
CUSTOMER_W_TER.TERRITORY,
SUM(ORDERFACT.TOTALPRICE)
FROM
CUSTOMER_W_TER INNER JOIN ORDERFACT ON CUSTOMER_W_TER.CUSTOMERNUMBER = ORDERFACT.CUSTOMERNUMBER
WHERE
ORDERFACT.YEAR_ID = 2004
GROUP BY
CUSTOMER_W_TER.TERRITORY

La requête « barchart_query » permet d’alimenter l’histogramme (« Bar Chart ») :

SELECT
PRODUCTS.PRODUCTLINE,
ORDERFACT.YEAR_ID,
SUM(ORDERFACT.TOTALPRICE) AS TOTAL
FROM
PRODUCTS INNER JOIN ORDERFACT ON PRODUCTS.PRODUCTCODE = ORDERFACT.PRODUCTCODE
INNER JOIN CUSTOMER_W_TER ON ORDERFACT.CUSTOMERNUMBER = CUSTOMER_W_TER.CUSTOMERNUMBER
WHERE
ORDERFACT.YEAR_ID IN (2003,2004)
AND CUSTOMER_W_TER.TERRITORY = 'Japan'
GROUP BY
PRODUCTS.PRODUCTLINE,
ORDERFACT.YEAR_ID

La vidéo qui suit illustre :

  • la création (et le test) des 2 premières requêtes SQL sous forme de Data Sources (CDA)
  • la création des 2 premiers composants: la liste déroulante & le diagramme en secteur
  • l’affectation des 2 requêtes aux composants respectifs


4. Mise en place des listeners (gestion des événements)

Certains composants sont « à l’écoute » d’autres composants via des « Listeners » (écouteurs): c’est de cette façon que les graphiques sont rendus dynamiques.

Ainsi dans notre exemple, les données présentées dans le diagramme en secteur (Pie Chart) dépendent de l’année sélectionnée dans la liste déroulante, tandis que celles de l’histogramme (Bar Chart) dépendent à la fois de l’année mais aussi de la zone cliquée depuis le camembert.

Deux paramètres sont à créer pour notifier les évènements possibles pour les mises à jour. Nommons ces paramètres « param_year » et « param_zone », ceux-ci étant définis depuis le menu « Components »

Tout composant qui est notifié (via son Listener) du changement de valeur d’un des paramètres est susceptible de se remettre à jour automatiquement. Ainsi les graphiques deviennent dynamiques; il suffit pour cela de positionner les paramètres correspondants dans les clauses WHERE des requêtes SQL.

La vidéo qui suit illustre :

  • la création du paramètre « param_year » et sa prise en compte dans le diagramme en secteur
  • la création de l’histogramme (Bar Chart)
  • la création du paramètre « param_zone » et sa prise en compte dans l’histogramme conjointement avec le paramètre année. On rend le Pie Chart cliquable en définissant sa propriété « Clickable » à « True » et en saisissant le code Javascript ci-dessous dans la propriété « Click Action ». La méthode fireChange permet d’alerter les listeners du changement de valeur d’un paramètre.
function(s,c,v){
      /* permet de changer la valeur de param_zone lors d'un clic sur une zone du PieChart
          s: série, c: catégorie, v: valeur    */
          Dashboards.fireChange('param_zone',c);
}


5. Finalisation du tableau de bord

Pour obtenir un tableau de bord présentable, il convient de faire quelques petites retouches :

 


Autres liens (très) utiles …

Voici quelques ressources incontournables qui devraient vous permettre d’exploiter au mieux la puissance des C*tools :

- Le site du projet: ctools.webdetails.org et celui de la société qui le porte, WebDetails

- Un guide de référence complet : [download id="64"]

- L’excellent tutoriel de Slawomir Chodnicki: « Creating Dashboards with CDE »

- Un tutoriel de TIKAL montrant l’élaboration d’un dashboard depuis un template sur des données en provenance de Bugzilla

- Le blog de Ambient BI, qui explique notamment les techniques pour incorporer des indicateurs et des barres proportionnelles dans des objets de type « Tableau » (vraiment génial, je conseille également la démo en ligne)

- Un article détaillant l’installation de Cygwin pour le setup de Ctools sous Windows

- Un très bon tutoriel conçu par StrateBI et un autre tutoriel pour la mise en place de filtres avancés (les 2 en espagnol)

- Des dashboards de démonstration conçus lors de sessions de formations aux CTools

- La section consacrée aux Ctools sur le forum pentaho

Un autre exemple… et les sources !

Je vous propose de télécharger l’exemple proposé, avec en bonus un tableau de bord un peu plus élaboré.

Ce dernier comprend des titres dynamiques, un graphique de type « Line Chart » ainsi qu’un objet « Table » très commode pour représenter des indicateurs d’évolution entre les années N et N-1 (vidéo ci-dessous)

Cliquer ici pour télécharger les sources

Note : le fichier « Demo CDE.zip » est à décompresser dans le répertoire /pentaho-solutions


=> Retrouvez plus de tutoriels Pentaho sur osbi.fr

L’integration de CMIS avec TYPO3

Fabrice Mouron novembre 3rd, 2011

Nous venons de réaliser une nouvelle extension pour TYPO3 « TYMIS » qui est la contraction de TYPO3 et CMIS. Cette extension permet à TYPO3 d’interagir avec tout entrepôt conforme avec le protocole CMIS.

Cette nouvelle extension va permettre aux entreprises utilisant des solutions d’ECM comme Alfresco, Sharepoint, Documentum, FilNet, Nuxeo, Vignette, etc., d’ouvrir leurs contenus aux utilisateurs de TYPO3. Les contenus de ces solutions pourront être accessible au travers d’un site intranet, extranet, internet ou d’un portail réalisé avec TYPO3.

Un rappel du protocole CMIS

L’accès et le partage des documents sont des enjeux stratégiques pour les entreprises et les collectivités, mais la multiplicité des outils stockant/contenant leurs documents ne leur facilite pas le travail. Il n’est pas rare d’avoir dans une même entreprise (voir un même service) des solutions différentes permettant la gestion, l’archivage et l’accès aux documents. Chaque solution (ECMs, GED, Outil Collaboratif…) gère bien des entrepôts de documents, mais chacune offre des moyens d’y accéder totalement différents.

L’idée de CMIS est de standardiser l’accès aux documents et aux d’informations les décrivant (métadonnées / métatags), et ainsi de pouvoir offrir l’accès à ces données de manière identique à partir de solutions différentes.
Lire la suite »

Geokettle 2.0. Une entrée dans la cour des grands

Cédric Darbon juillet 20th, 2011

Depuis peu, la Release Candidate de Geokettle 2.0 est disponible en téléchargement sur Sourceforge . Pour rappel, cet ETL basé sur Pentaho Data Integration ajoute à ce dernier des fonctionnalités dédiées à la manipulation de l’information géographique. Si les premières versions de GeoKettle proposaient déjà des fonctionnalités intéressantes (cf. billet précédent), il faut bien reconnaître que pour cette version, les équipes de Spatialytics ont clairement mis le paquet afin de proposer une version corrigée et très enrichie de Geokettle. Cette dernière, encore basée sur un coeur PDI 3.2 fonctionne en 32 ou 64bits ; des réflexions sont en cours pour porter les fonctionnalités spatiales vers les versions 4.x de PDI.

Premières impressions

Un installateur dédié

Geokettle dispose désormais d’un script d’installation dédié. L’installation par décompression d’un zip reste bien entendu possible mais désormais, les géomaticiens n’auront plus d’excuses pour ne pas installer cet outil sur leur poste.

Une prévisualisation cartographique des données

Un mécanisme de prévisualisation cartographique est désormais disponible pour toutes les étapes. Un onglet « Vue géographique » permet de visualiser la représentation des différentes colonnes géométriques présentes dans le flux. Les actions de zoom, de centrage, d’interrogation d’objets et de personnalisation des styles cartographiques sont également proposées. A l’usage, cet onglet se révèle bien pratique pour vérifier sur des jeux de données restreints que les traitements à réaliser sont corrects avant de lancer ces derniers sur des gros volumes.

Prévisualisation cartographique des données

Lire la suite »

Contraintes des développements mobiles et les réponses apportées par Sencha Touch

Alexis Venner mai 19th, 2011

Ces dernières années ont vu l’arrivée de nouveaux terminaux mobiles dont les interfaces se sont de plus en plus adaptées aux contraintes de leur environnements. Nous allons tenter dans cet article d’identifier ces contraintes et voir quelles réponses apporter dans les applications web via l’utilisation du framework Sencha Touch.

Lire la suite »

Solution générique d’impression de pages web

Charles-Henry Vagner mars 9th, 2011

Préambule

Nous recevons un nombre croissant de demandes de nos clients qui concernent la génération d’un fichier PDF ou d’une image à partir d’une page web issue d’une application métier, un extranet ou encore un intranet.

Facile me direz-vous : il suffit d’installer une imprimante PDF telle que PDF Creator ou encore doPDF. Effectivement… Sauf que cette opération nécessite une installation sur le PC de l’utilisateur et que c’est justement ce qu’on essaie d’éviter avec une application web !

Le besoin est réel et il n’existe pas aujourd’hui de solution générique qui fournisse des résultats concluants.

Bien souvent, le réflexe reste de développer un nouveau module pour l’occasion qui traite le cas spécifique de l’impression des informations avec une présentation connue à l’avance.

Partant de ce constat, nous avons décidé de mettre en œuvre une solution générique de capture de pages web côté serveur, avec un fichier produit qui soit le plus fidèle possible au résultat obtenu avec un navigateur classique.

Dans ce billet, je détaille mes pistes de réflexion en exposant ma démarche par étapes et j’expose les résultats obtenus : de l’impression rapide côté client à l’adaptation d’une librairie utilisée côté serveur.

Lire la suite »

Manipuler le GML avec Pentaho Data Integration

Cédric Darbon mars 8th, 2011

1. Contexte

L’utilisation du format GML est aujourd’hui courante dans les fichiers d’échanges XML. Parallèlement, les outils ETL procurent de réels avantages pour mettre en place les chaines de traitements liées à ces besoins d’échanger (changements de format et/ou de structure de la données, échanges entre plateformes, etc.). Aujourd’hui, et à moins de disposer d’un ETL spatial évolué ou de faire appel à des librairies externes comme OGR, il faut bien reconnaitre que la manipulation du GML dans les ETL Open source non spatiaux peut s’avérer fastidieuse, ce format étant par nature assez verbeux (emboitement de nœuds successifs). Pour les amateurs de Kettle (Pentaho Data Integration), il existera pourtant prochainement une solution : Exploiter conjointement la librairie JTS et la future brique améliorée de lecture XML disponible dans la prochaine version PDI 4.2 (en cours de développement). Les paragraphes suivants expliquent la démarche à suivre pour réaliser ce genre de traitements.

2. Mise en pratique

Pour notre exemple, nous disposons des outils suivants :

Pentaho Data Intégration permet nativement de faire appel à des librairies Java au sein des étapes « Appel script interprété Rhino ». Pour pouvoir exploiter la librairie JTS à travers ces étapes, il faut déposer au préalable les jars « jts-1.11.jar » et « jtsio-1.11.jar » dans le dossier libext de PDI.

2.1. Principe

Les transformations proposées ci-après correspondent à deux besoins simples :

  • Comment lire un contenu GML pour pouvoir l’intégrer en base de données spatiale ?
  • Comment produire un fichier XML avec du contenu au format GML à partir d’une base de données spatiale ?

2.2. Intégrer un contenu GML en base de données spatiale

Dans cet exemple, nous disposons d’un fichier XML regroupant des îlots agricoles (entité administrative utilisée par les agriculteurs dans le cadre de la Politique Agricole Commune pour prétendre au versement d’aides européennes) et des parcelles culturales (limites d’une même culture = les « champs »).

  • Un îlot peut contenir une ou plusieurs parcelles culturales et possède une géométrie de type « polygone » équivalente à l’union géométrique des parcelles qui le compose,
  • Une parcelle possède une géométrie de type « polygone » et ne peut être rattachée qu’a un seul îlot.

Lire la suite »

Un plugin Kettle pour Pentaho Metadata

Sylvain Decloix janvier 21st, 2011

Préambule

Il y a quelques temps déjà, je suis tombé sur un plugin très intéressant pour le serveur Pentaho, à savoir le MetadataSample Plugin.

Ce petit plugin développé par Andy Grohe, démontre comment on peut interagir avec le Web Service utilisé par le WAQR de Pentaho (Web Ad Hoc Query Reporting) afin de proposer d’autres possibilités de présentation pour l’interface utilisateur (GUI).

Pour rappel, le WAQR, c’est le module web disponible dans Pentaho (versions CE & EE) qui permet de construire un rapport à partir de la couche de métadonnées, sans aucune connaissance du SQL par l’utilisateur final. C’est assez pratique (par exemple) pour réaliser des exports Excel en manipulant simplement des vues et des colonnes métier. Je détaillerai tout ceci dans des prochains articles…

Après avoir développé cet été le plugin « BIRT ODA Pentaho Metadata Plugin », je me suis dit qu’il était finalement intéressant de mixer le travail d’Andy et le mien pour permettre à ce bon vieux Kettle de récupérer lui aussi des données depuis des domaines de métadonnées « Pentaho Metadata ».

Quel intérêt ?

Prenons un exemple simple, sur la base de données SampleData embarquée dans le serveur Pentaho de démo.

Imaginez que vous souhaitiez générer avec Kettle un fichier Excel synthétisant le montant total des ventes par gamme de produit (ProductLine) et par client (CustomerName), tout ça pour la France.

Votre traitement va ressembler à ceci :

L’ordre SQL à cela (3 jointures, un GROUP BY, une clause WHERE) :

SELECT
CUSTOMER_W_TER.TERRITORY,
CUSTOMER_W_TER.COUNTRY,
CUSTOMER_W_TER.CUSTOMERNAME,
PRODUCTS.PRODUCTLINE,
SUM (ORDERDETAILS.QUANTITYORDERED * ORDERDETAILS.PRICEEACH) AS TOTAL
FROM
PRODUCTS INNER JOIN ORDERDETAILS ON PRODUCTS.PRODUCTCODE = ORDERDETAILS.PRODUCTCODE
INNER JOIN ORDERS ON ORDERDETAILS.ORDERNUMBER = ORDERS.ORDERNUMBER
INNER JOIN CUSTOMER_W_TER ON ORDERS.CUSTOMERNUMBER = CUSTOMER_W_TER.CUSTOMERNUMBER
WHERE
CUSTOMER_W_TER.COUNTRY = 'France'
GROUP BY
CUSTOMER_W_TER.TERRITORY,
CUSTOMER_W_TER.COUNTRY,
PRODUCTS.PRODUCTLINE,
CUSTOMER_W_TER.CUSTOMERNAME

Avec le plugin d’extraction depuis une source Pentaho Metadata, cela va être un peu plus simple, puisque tout se gère dans une interface spécifique :

Dans ce cas, il suffira juste de sélectionner les 5 colonnes métiers utiles, et selon le type d’agrégateur pour le champ « Total » défini dans la couche de métadonnées, la consolidation sera automatique…

Bien sûr les colonnes métiers peuvent être traduites en français, italien, espagnol, etc… Pentaho Metadata gère le i18n.

Dans la vidéo qui suit, vous allez vous rendre compte que selon l’utilisateur avec qui on se connecte, l’accès aux modèles métiers est sécurisé: seul « Joe » accède aux 3 modèles (mais pas Suzy ou Pat). Cela serait valable également pour les colonnes métiers (sauf que dans le metadata de démo ce n’est pas configuré). On pourrait également dicter des règles filtrage au niveau des lignes retournées et non plus des colonnes (« row-level filtering ») : par exemple Joe ne pourrait voir que les données pour la France, Suzy pour les USA et Pat pour l’Italie…

Démonstration

Rien de telle qu’une vidéo pour mieux appréhender le fonctionnement du plugin :

Installation

Le plugin est disponible en version beta (v0.8) sur labs.atolcd.com, où vous trouverez d’ailleurs d’autres contributions plutôt intéressantes dans le domaine de l’OSBI, mais aussi de l’ECM, des SIG et des CMS :

  • Un plugin Kettle pour écrire directement dans des DataList Alfresco via le standard CMIS :-)
  • La version 1.0 de Geo Analysis Tool (portée sous GWT). J’en reparlerai ici bientôt également…

Pour que le plugin fonctionne, vous devez utiliser obligatoirement Kettle 4.0 ou 4.1 et un serveur Pentaho 3.6 ou 3.7.

Guide d’installation :

  • Décompresser le fichier « PentahoMetadata_Kettle_Plugin-0.8.zip » dans le répertoire d’installation de Kettle \plugins\steps. Un répertoire « MetadataPlugin » est créé. Celui-ci contient la librairie java, l’icône de la brique au format png ainsi qu’un fichier « mqlQuery.xaction »
  • Copier le fichier « mqlQuery.xaction » dans le répertoire \pentaho-solutions\system du serveur Pentaho
  • Démarrer votre serveur Pentaho , lancer Kettle puis tester cette nouvelle étape, vous la trouverez dans le dossier « Extraction »

Pourquoi une version beta ?

Ce plugin a été finalement développé en très peu de temps, surtout pour le « fun ». :-)

Bien sûr il y a des améliorations à apporter :

  • Pouvoir ajouter simplement une condition de filtrage dans l’étape via une interface « user friendly » et non une contrainte MQL (dont il faut connaître la syntaxe XML)
  • Rajouter des contrôles d’erreurs (ajout d’exceptions Java) notamment lorsqu’il y a des soucis d’accès au web service et/ou au serveur Pentaho (ça manque)
  • Et surtout, adapter le plugin aux évolutions de la plate-forme afin d’attaquer d’ici peu l’API prévue dans Pentaho 4. James Dixon a déjà fourni quelques éléments sur ce sujet fin 2010 dans son « JimmyLabs », de la doc techniquement fortement intéressante !

Si jamais vous trouvez des bugs, vous pouvez les notifier dans le gestionnaire de bugs afin qu’une version stable 1.0 voie le jour ;-)

Ah j’oubliais, lors du développement du plugin Kettle pour Alfresco, nous avons commencé à rédiger un document assez détaillé (merci Vincent) pour vous aider à coder vous-même vos propres plugins Kettle. A suivre donc, celui-ci sera bientôt disponible sur notre blog technique !

Pentaho: Les différences entre la version gratuite et payante

Sylvain Decloix décembre 17th, 2010

Pentaho est une suite décisionnelle open source commerciale très ouverte dont les différences fonctionnelles entre la version libre gratuite (CE=Community Edition) et la version payante (EE=Enterprise Edition) sont limitées.

Le degré d’ouverture est d’ailleurs bien plus élevé que chez Actuate BIRT ou JasperSoft.

Voici un document de synthèse qui présente dans le détail les différences fonctionnelles entre les 2 versions de Pentaho. Bien sûr, n’oubliez pas que la version Enterprise permet en outre de bénéficier du support directement auprès de l’éditeur !

Ce document, valable pour Pentaho 3.7, vous permettra de constater que la version gratuite de Pentaho permet de déployer une plate-forme décisionnelle complète, et ceci avec une grande qualité d’intégration.

Télécharger le comparatif : Pentaho – Différences versions CE et EE

Prévisualiser le comparatif :

GWT 2.1 Places – Partie II

Thomas Broyer novembre 23rd, 2010

Cet article est le second d’une série publiée à l’origine en anglais sur mon blog personnel.

J’ai déjà décrit le cœur des places GWT 2.1 et je vais maintenant me concentrer sur les fonctionnalités optionnelles.

Confirmation par l’utilisateur avant de naviguer

Dans de nombreuses applications, vous voulez avoir la confirmation de l’utilisateur avant de naviguer ; notamment lorsque l’utilisateur fait des modifications et ne les a pas enregistrées. C’est relativement aisé avec les places GWT 2.1 : il suffit d’enregistrer un PlaceChangeRequestEvent.Handler sur le bus d’événements et d’appeler la méthode setWarning du PlaceChangeRequestEvent avec une valeur non-nulle, qui sera alors utilisée comme message de demande de confirmation.

Lorsqu’on appelle goTo sur le PlaceController, avant de changer de place courante, celui-ci commence en fait par émettre un PlaceChangeRequestEvent. Une fois l’événement dispatché, la place courante ne sera effectivement modifiée, et le PlaceChangeEvent dispatché, que dans deux cas :

  • la propriété warning de l’événement vaut null, ou
  • la propriété warning de l’événement n’est pas nulle, mais l’utilisateur a confirmé la navigation. Cette confirmation est demandée via une boîte de dialogue (native au navigateur), la propriété warning de l’événement étant utilisée comme message présenté à l’utilisateur.

De plus, lorsque l’utilisateur quitte l’application (navigue vers un autre site, ou ferme la fenêtre ou l’onglet), un tel PlaceChangeRequestEvent est également dispatché (la prochaine place étant fixée à Place.NOWHERE), et une valeur non-nulle pour la propriété warning de l’événement provoquera également une demande de confirmation (sans entrer dans les détails, la propriété warning est alors utilisée comme message de l’événement Window.ClosingEvent).

Intégration avec RequestFactory

GWT 2.1 ne fournit pas d’intégration directe avec RequestFactory. On peut cependant trouver dans l’exemple Expenses un aperçu de ce qui viendra dans une prochaine version, sous la forme de deux places liées à, respectivement, un type et une instance d’EntityProxy : la ProxyListPlace représente la liste des objets d’un type donné, alors que la ProxyPlace indique une opération (création, détails, ou modification) sur une instance identifiée.

Intégration avec l’historique du navigateur

L’intégration avec l’historique du navigateur implique de :

  1. sérialiser la place actuelle dans l’URL, afin qu’elle puisse être mise en signet/favori/bookmark, et créer une entrée dans l’historique de navigation du navigateur, et
  2. désérialiser l’URL vers une place, et dispatcher les événements appropriés sur le bus d’événements pour mettre à jour la place courante.

Le premier est utilisé lorsque la place change suite à un appel à la méthode goTo du PlaceController, alors que le second est déclenché par le navigateur lorsque l’utilisateur soit navigue dans son historique par les boutons « page précédente » et « page suivante » du navigateur, soit charge une URL générée par le premier (à partir d’un signet, d’un lien dans une page web, un e-mail ou sa messagerie instantanée).

Pour utiliser cette fonctionnalité, vous devez d’abord créer des PlaceTokenizers pour traduire les history tokens vers / depuis des places, puis une interface (vide), descendant de PlaceHistoryMapper et annotées avec @WithTokenizers pour déclarer les PlaceTokenizers à utiliser, interface que vous instancierez avec GWT.create() et inscrirez, via un PlaceHistoryHandler, avec le PlaceController, le bus d’événements et une place par défaut (utilisée quand il n’y a aucun history token, ou lorsque celui-ci ne peut pas être traduit en place).

   @WithTokenizers(FooPlaceTokenizer.class, BarPlaceTokenizer.class)
   interface MyPlaceHistoryMapper extends PlaceHistoryMapper {
   }
 
   PlaceHistoryMapper historyMapper = GWT.create(MyPlaceHistoryMapper.class);
   PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper);
   historyHandler.register(placeController, eventBus, defaultPlace);
Comment le PlaceHistoryHandler traduit les history tokens en places ?

Chaque PlaceTokenizer est associé à un préfixe grâce à une annotation @Prefix. Le PlaceHistoryHandler découpe l’history token sur le premier deux-points, compare la partie gauche aux préfixes qu’il connait, et instancie, avec GWT.create(), le PlaceTokenizer correspondant afin d’appeler sa méthode getPlace en passant la partie droite de l’history token en argument.

Comment le PlaceHistoryHandler traduit les places en history tokens ?

PlaceTokenizer est une classe générique (paramétrée) définie exactement de la sorte : PlaceTokenizer<P extends Place>. Lorsque le générateur de code travaille sur le PlaceHistoryHandler, il examine les PlaceTokenizers et extrait leur argument générique P. Cette information est ensuite utilisée à l’exécution pour associer une place à sa classe PlaceTokenizer, de sorte que le PlaceHistoryHandler puisse l’instancier avec GWT.create() et appeler sa méthode getToken. La valeur retournée est alors préfixée du @Prefix du PlaceTokenizer et d’un deux-points comme séparateur, et le résultat utilisé finalement comme history token.

Utiliser une fabrique pour les PlaceTokenizers

Votre PlaceTokenizer peut avoir des dépendances sur d’autres objets, mais il n’y a pas de place pour la personnalisation dans l’algorithme ci-dessus, qui crée une nouvelle instance de PlaceTokenizer chaque fois qu’il en a besoin pour l’oublier instantanément. C’est là que le PlaceHistoryHandlerWithFactory fait son entrée : vous héritez de cette interface au lieu de PlaceHistoryHandler et appelez setFactory avec une fabrique (ou un fournisseur ; en anglais respectivement factory et provider) de PlaceTokenizers juste avant de l’initialiser.

PlaceHistoryHandlerWithFactory a un argument de type générique, que le générateur de code utilisera pour lister toutes les méthodes sans argument dont le type de retour est assignable à PlaceTokenizer. La classe générée appelera ces méthodes au lieu d’utiliser GWT.create() quand elle aura besoin d’un PlaceTokenizer. Les méthodes peuvent également être annotées avec @Prefix pour remplacer l’annotation éventuellement présente sur la sous-classe de PlaceTokenizer. Enfin, les classes PlaceTokenizer que votre fabrique peut fournir ne doivent pas être listées dans l’annotation @WithTokenizer, qui devient donc facultative.

Votre fabrique peut vraiment être n’importe quelle classe ou interface, vous pouvez donc même utiliser un Ginjector si vous utilisez GIN pour l’injection de dépendances.

Utiliser son propre PlaceHistoryMapper, sans PlaceTokenizer

Vous n’êtes en fait pas tenu d’utiliser GWT.create() sur un ProxyHistoryMapper, et donc de vous appuyer sur le code généré à base de PlaceTokenizers ; vous pouvez très bien implémenter l’interface vous-même, comme bon vous semble. Et non seulement c’est techniquement possible, mais c’est un cas d’utilisation explicitement reconnu (vous pouvez me croire sur ce coup, c’est moi qui ai contribué le patch).

Et pour la suite ?

Le prochain article traitera des activités GWT 2.1, qui se situent au-dessus des places, vous libérant de la gestion des événements décrits jusque là. C’est ce que l’équipe GWT appelle le Framework MVP de GWT 2.1 même si en l’occurence, bien qu’elles aident à la mise en place du pattern MVP, elles n’obligent en rien son utilisation ; et vous aurez probablement aussi besoin de construire des composants MVP qui ne sont pas des activités, donc… Ceci étant, les activités GWT 2.1 apportent une API avec laquelle il fait vraiment bon travailler, stay tuned!

GWT 2.1 Places

Thomas Broyer novembre 9th, 2010

Cet article est le premier d’une série publiée à l’origine en anglais sur mon blog personnel.

Ray Ryan a fait le buzz l’an dernier à Google I/O 2009 avec sa présentation des Meilleures Pratiques pour l’Architecture de votre Application GWT (Google Web Toolkit Architecture: Best Practices For Architecting Your GWT App). Mais ce qui a peut-être fait le plus de bruit était sans doute moins ce qui a été dit que ce qui n’a été que brièvement évoqué : le Place Service. Depuis lors, de nombreux développeurs (moi y compris) se sont essayés au concept, mais Google l’a finalement intégré dans GWT 2.1, sorti récemment.

Qu’est-ce qu’un lieu ?

Dans n’importe quelle application, les applications web en particulier, qui n’ont que rarement recours au concept de fenêtre (et si vous voulez mon avis, les développeurs d’applications web devraient s’efforcer de faire de ce « rarement » dans un « jamais »), on se situe par une notion de lieu (place en anglais): « où suis-je ? », « aller à … », etc. (d’ailleurs, j’ai bien utilisé le verbe « se situer », et on utilise également couramment « s’orienter », « se diriger », ou encore « naviguer »).

Des exemples de lieux incluent : votre boîte de réception, les résultats de recherche pour « GWT Places », le profil de l’utilisateur « t.broyer », la note de frais référencée « abcdefgh », etc.

L’idée est donc d’utiliser cette notion de lieu pour gérer la navigation dans l’application, en se basant sur des événements de « changement de lieu ».

Le PlaceService ici sert de pont entre ces événements et la gestion d’historique du navigateur (ceci mériterait un article complet, mais disons qu’il s’agit de rendre effectifs les boutons « page précédente » et « page suivante » du navigateur, tout en conservant l’application sur une unique page web). Le PlaceService est, et doit rester, le seul composant de l’application qui gère l’historique du navigateur et réagit à ses changements.

Démystifier les idées fausses

Avant d’entrer dans les détails, mettons certaines choses au clair : les lieux n’ont rien à voir avec le pattern MVP, et rien à voir avec la notion d’un bus d’événements global à l’application (qui n’a lui non plus rien à voir avec MVP). Vous pouvez utiliser chacun d’eux de manière totalement indépendante. Il devient monnaie courante de tous les utiliser en même temps, mais chacun répond à des besoins différents. Cela signifie également que vous n’avez pas besoin de comprendre ces autres concepts dont Ray Ryan a parlé dans sa présentation (MVP, bus d’événements, command-pattern pour les RPC, etc.) afin de comprendre les places.

Alors à quoi cela ressemble-t-il dans GWT 2.1?

GWT 2.1 matérialise le PlaceService à deux niveaux d’abstraction (lieux et activités, places et activities), et l’intégration optionnelle avec d’autres fonctionnalités de GWT (History pour l’instant, et RequestFactory à venir dans une prochaine version), sous la forme des modules com.google.gwt.place.Place et com.google.gwt.activity.Activity respectivement.

Le cœur des places GWT 2.1 est le PlaceController, que vous utiliserez pour naviguer de lieu en lieu, mais nous allons commencer par examiner ce à quoi une place ressemble dans GWT 2.1 et ce qu’elle représente.

Qu’est-ce qu’une place GWT 2.1?

Dans GWT 2.1, les places sont des objets légers qui étendent la classe abstraite Place. Elles sont généralement jetables et immuable, même si cela n’est pas obligatoire ; et il y a quelques bonnes raisons d’utiliser des places non jetables, comme nous le verrons plus tard (je ne vois par contre aucune raison pour avoir des places modifiable).

Vous pouvez définir autant de sous-classes de Place que nécessaire, associées ou non à des « données » (l’identifiant d’un enregistrement, la requête d’une recherche, etc), et vous créerez une nouvelle instance à chaque fois que vous naviguerez dans votre application. La classe Place ne définit aucune méthode, mais les sous-classes doivent implémenter correctement les méthodes Object.equals(Object) et Object.hashCode().

Présentation du PlaceController

Le PlaceController est un objet qui gère la place actuelle (où vous êtes) et la navigation entre les places. Vous ne devriez donc jamais avoir plus d’une instance PlaceController par application.

Pour permettre à votre application de réagir à des changements de lieux (pour mettre à jour l’interface utilisateur et l’état de l’application de sorte qu’elle reflète la nouvelle place), le PlaceControler déclenche des événements sur un bus d’événements. Vous n’avez pas besoin de vraiment comprendre la notion de bus d’événements pour poursuivre la lecture ; disons simplement que, au lieu d’enregistrer vos gestionnaires d’événements sur le PlaceController lui-même, vous les ajouterez à un autre objet (le bus d’événements, dont soit dit en passant il ne devrait également y avoir qu’une unique instance par application), et vous initialiserez le PlaceController afin qu’il lance ses événements sur ce bus.

Le point d’entrée de votre application contiendra donc généralement ce genre de code :

  EventBus eventBus = new SimpleEventBus();
  PlaceController placeController = new PlaceController(eventBus);

Par défaut, le PlaceController est initialisé avec pour place actuelle Place.NOWHERE (en d’autres termes, placeController.getWhere() retourne Place.NOWHERE). Pour naviguer vers un autre endroit, vous passerez une place à la méthode goTo du PlaceController, par exemple :

  placeController.goTo(new MyPlace());

Cela aura pour effet de modifier l’emplacement actuel, puis de lancer un PlaceChangeEvent sur le bus d’événements, événement que vos composants vont écouter en enregistrant un PlaceChangeEvent.Handler :

  eventBus.addHandler(PlaceChangeEvent.TYPE, new PlaceChangeEvent.Handler() {
    public void onPlaceChange (PlaceChangeEvent event) {
      Place newPlace = event.getNewPlace();
      ...
    }
  });
Où aller maintenant?

Ce n’était qu’un aperçu du cœur des places GWT 2.1, afin que vous puissiez saisir les concepts sous-jacents.

Je parlerai de la confirmation par l’utilisateur de la navigation, de l’intégration avec l’historique du navigateur (ce qui signifie aussi des places enregistrables en tant que favoris/bookmarks dans le navigateur), et des activités (une API de plus haut niveau qui, entre autres, aide à l’utilisation du pattern MVP) dans les prochains articles.

Suiv »