Confluence est un wiki pour entreprise édité par la société Atlassian basée en Australie. Le wiki fait partie de la suite logicielle Jira Studio, disponible toute hébergée ou on site. Un SDK est à disposition des développeur de plugins pour enrichir les produits de la suite. Nous allons donc faire un premier plugin afin d’ajouter une fonctionnalité au wiki, ça vous permettra de découvrir l’outillage et les différentes API disponibles ainsi que leur maturité.
D’un point de vu fonctionnel notre plugin sera très simple : on va ajouter des notifications au wiki. Pour ce qui est de l’UX, on va s’inspirer du travail de Catalin Rosu chez Red Team Design dans son billet Cool notification messages with CSS3 & Jquery.
Un framework de plugin construit sur OSGI est embarqué dans Confluence. Il permet d’étendre au runtime les fonctionnalités existantes avec des plugins packagés sous forme de Jar. On va donc utiliser le SDK d’Atlassian (basé sur Maven) pour générer le template de notre plugin, il embarquera des fichiers de configuration, du code Java, du Javascript (avec JQuery) et un peu de CSS3.
Concernant les API, on va utiliser :
- Sur le serveur :
- l’API Confluence bien entendu.
- l’API Shared Acces Layer (SAL) : une API transverse aux produits Atlassian.
- Atlassian REST API (basé sur Jersey) pour exposer un service RESTfull.
- Google Collections pour manipuler nos données (functional style programming)
- Joda Time pour les dates.
- Sur le client :
- La bibliothèque Atlassian User Interface (AUI), en particulier Atlassian JavaScript (AJS).
- JQuery
- CSS3
Sans détour, rentrons directement dans le vif du sujet (sources).
Setup
Installer le SDK, puis dans votre workspace lancer un terminal et faites :
atlas-create-confluence-plugin fr.taraxe.confluence live-notification-plugin enter enter
Allez dans le dossier du projet qui vient d’être créé, puis faites :
mvn confluence:run
Si c’est la toute première fois, ca va mettre un certain temps : Maven va télécharger un grand nombre de dépendances dont le WAR de Confluence qui pèse tout de même 140Mo pour Confluence 3.5.
Allez dans voter navigateur à l’URL http://localhost:1990/confluence, la page de login doit s’afficher et vous pouvez vous authentifier avec admin/admin. Pressez Ctrl + c pour arreter le serveur. Par la suite vous pourrez lancer le serveur avec « mvn confluence:debug » pour tirer profit du mode debug. Pour redéployer le plugin à chaud sur une instance qui tourne, ouvrez un autre terminal et faites « mvn confluence:cli » puis « pi » dans le promp à chaque fois que vous voulez redéployer.
Vous pouvez maintenant importer le projet dans votre IDE comme un projet Maven, on est prêt à commencer.
Avant de commencer
Regardons un peu ce qui a été bootstrapé par le SDK :
Trois choses importantes :
- le fichier pom.xml (Project Object Model), documentez vous sur Maven si vous ne connaissez pas.
- le fichier atlassian-plugin.xml : le descripteur du plugin, c’est dans ce fichier que l’on déclarera les composants de notre plugin.
- le code et les tests, les fichiers .java. Vous notez qu’une macro d’exemple avec les tests unitaires et d’intégration ont été générés.
Les modules
Un plugin est composé de modules, il en existe environ 30 differents avec des types et rôles particuliers.
Dans note cas, nous avons besoin de 3 modules (ou composants) principaux :
Module Event Listener
On va s’en servir pour écouter les événements de Confluence, à savoir le dispatch de Notification. On le déclare de la manière suivante dans le fichier atlassian-plugin.xml et son implémentation :
<component name="Notification Event Listener" class="fr.taraxe.confluence.NotificationListener" key="notificationListener"/>
Module Component
C’est le principal composant du plugin, il est responsable de la logique « métier » (c’est la que JodaTime et Google Collections interviennent). On le déclare de la même manière dans le fichier atlassian-plugin.xml :
<component name="Live Notification Manager" class="fr.taraxe.confluence.LiveNotificationManager" key="liveNotificationManager"/>
Voici son code.
Module Rest Service
Ce module a la responsabilité d’exposer un service REST qui pourra être consommé par des clients. Voici sa déclaration et son implémentation :
<rest name="Live Notification REST Service" key="live-notifification-rest" path="/notify" version="1.0"/>
Le service est exposé à cette URL : http://localhost:1990/confluence/rest/notify/latest/now, il renvoie au format JSON les dernières notifications pour un utilisateur donné (passé en paramètre).
Remarques
Si vous êtes familier avec Spring DI, vous aurez certainement remarqué que nos composants ont l’air d’être dans un conteneur avec inversion de contrôle. En effet, chacun se voit injecter des composants tiers par le constructeur. C’est exactement le cas, en arrière plan c’est Spring qui va gérer nos composants : le fichier atlassian-plugin.xml sera transformé en des sous contextes applicatifs Spring DM pouvant importer des services et/ou en exposer d’autres (pour les curieux). C’est Spring via OSGI qui va résoudre les dépendances de nos composants au runtime et faire leur injection à grand coup d’autowiring par type sur les constructeurs. Pour plus d’information sur l’architecture du système de plugin ou si vous voulez plus de contrôle sur le cycle de vie des composants de vos plugins, voici de la documentation. De cette manière le framework de plugin arrive à masquer beaucoup de la complexité sous jacente pour 99% des cas d’utilisation, pour le reste il faudra mettre les mains dedans. Cet un bon exemple d’utilisation de la modularité standardisée OSGI, qui est un peu moins hype ces derniers temps dans l’écosystème Java du fait de sa complexité.
La vue
Les éléments de la vue sont déclarés comme suit dans atlassian-plugin.xml :
<web-panel key="${project.groupId}.${project.artifactId}.webpanel" location="atl.confluence.header"> <resource name="view" type="velocity"> <![CDATA[ $webResourceManager.requireResource("fr.taraxe.confluence.live-notification-plugin:live-notification-resources") ]]> </resource> </web-panel> <web-panel key="${project.groupId}.${project.artifactId}.webpanel2" location="atl.confluence.header"> <resource name="view" type="velocity" location="template/notification.vm"/> </web-panel> <web-resource key="live-notification-resources" name="Live Notification web resources"> <dependency>confluence.web.resources:ajs</dependency> <resource type="download" name="notification.css" location="css/notification.css"/> <resource type="download" name="notification.js" location="js/notification.js"/> <!-- Using these *only* works locally (3.4.8), but does not work on production (3.4.8) --> <context>atl.general</context> <!-- Additional Confluence specific contexts makes it work on production too! --> <context>dashboard</context> <context>space</context> <context>page</context> <context>main</context> </web-resource>
On déclare une Web Resource, c’est à dire une ensemble d’éléments qui vont être utiles pour les vues (un script notification.js et un css notification.css) qu’on intègre avec 2 modules Web Panel.
Voici le fichier atlassian-plugin.xml en entier à la fin.
Vous notez qu’on y a ajouté un module Component Import pour un service du SAL, le UserManager, ainsi qu’une Resource pour l’internationalisation, notification.properties.
Conclusion
A chaque fois qu’un utilisateur sauvegarde une page à laquelle la notification par mail est active, on est notifié de son activité :
Comme vous avez pu le voir, créer son premier plugin pour Confluence est relativement simple : la documentation est de bonne qualité et les API sont matures. C’est de la programmation assez haut niveau qui nous a permis de réaliser notre notre feature tout en cachant beaucoup de complexité.
Le source est disponible sur BitBucket sous licence Apache License, Version 2.0 (ASL). Vous savez que votre feedback est le bienvenu ainsi que vos questions.
[…] des technologies web. Ces extensions viennent s’intercaler entre les plugins (aller lire ce bon billet pour comprendre comment faire un plugin Confluence) et les macros utilisateurs et offrent un moyen supplémentaire pour faciliter l’adoption des […]
[…] mon précédent billet sur le développement de plugin pour Confluence, j’ai évoqué le style de programmation […]
[…] de base : il contient par défaut une macro et quelques tests comme vous avez pu le voir dans le billet sur le dev de plugin Confluence. Nous allons modifier notre plugin pour intégrer Scala, réécrire le code de cette macro en […]