We apologize for untranslated text, you can use the Google Translation button to get an automatic translation of the web page in the language of your choice.

JCMS 5.7: Plugins development (french)

JCMS 5.7 introduit un mécanique d'extension par module (ou plugin). L'objectif des modules est triple :

  1. Fournir un mécanisme d'extension à JCMS. Ces extensions peuvent concerner l'ajout de fonctionnalité (p. ex. nouvelles portlets, Blog, podcast, …) ou la modification de fonctionnalités natives de JCMS (droits, authentification, recherche, …) ;
  2. Offrir une solution simplifiée d'empaquetage, de diffusion et d'installation de ces extensions. L'objectif est d'atteindre la simplicité du plug'n play pour les modules JCMS.
  3. Garantir un meilleur isolement des développements spécifiques. Ainsi lors d'une migration de versions de JCMS, dans le cas nominal, il suffira de reprendre les données, le module du projet, les modules externes et de les déployer dans la nouvelle version de JCMS.

Cette nouvelle mécanique doit aussi permettre à d'autres acteurs que Jalios (éditeurs, intégrateurs et utilisateurs) de diffuser leurs propres modules. Chaque module possède sa propre licence d'utilisation.

JCMS a été entièrement revu pour être extensible par module. Ainsi les modules peuvent intervenir dans la majeure partie des interfaces et de la mécanique interne de JCMS sans avoir à modifier les fichiers d'origine.

1. Le gestionnaire de module

Le gestionnaire de modules est accessible depuis l'espace d'administration. Il permet d'installer, de paramétrer, de créer, d'activer et de désactiver des modules JCMS.

Un module JCMS se présente sous forme d'une archive zip contenant un descripteur, le fichier plugin.xml, et toutes les ressources nécessaires au fonctionnement du module. Le fichier descripteur contient à la fois les informations sur le module (son nom, sa description, sa version, ses dépendances, …), les règles d'empaquetage, de déploiement et d'intégration dans JCMS.

Les modules JCMS sont diffusés sur le site JaliosXperience, à l'adresse suivante :

http://support.jalios.com/plugin/

L'interface du gestionnaire de modules affiche, dans la boîte Nouveautés, les derniers modules diffusés sur JaliosXperience.

Screenshot

Fig. 1. L'interface du gestionnaire de module.

1.1 Ajout d'un nouveau module

Voici la procédure à suivre pour installer un module :

  1. Récupérez l'archive zip d'un module, par exemple en la téléchargeant sur JaliosXperience ;
  2. Dans la boîte Déposer un module, sélectionnez l'archive du module, cochez l'option Déployer automatiquement et cliquez sur le bouton Déposer un module ;
  3. Redémarrez JCMS ;
  4. Le module est maintenant initialisé. Dans la liste des modules, cliquez sur le nom du module pour accéder à l'interface de gestion du module. Consultez sa documentation pour effectuer les éventuels paramétrages et compléments d'installation.
Screenshot

Fig. 2. L'interface de gestion d'un module.

Les différents états d'un module sont :

  • Chargé : une archive de module a été trouvée mais n'a pas encore été déployée ;
  • Initialisé : l'archive est déployée et tous les branchements dans JCMS fonctionnent.

Un module peut dépendre d'autres modules. Avant d'installer un module, il faut donc veiller à installer préalablement tous les modules dont il dépend. Cette liste de modules est précisée dans la fiche d'information du module. Si l'un de ces modules est absent, le module n'est pas initialisé.

Si lors du déploiement, certains fichiers du module doivent écraser des fichiers existants alors ceux-ci sont copiés dans un répertoire de sauvegarde (WEB-INF/plugins/{Name}Plugin/backup/).

Si des erreurs se sont produites au démarrage du module, elles sont listées dans l'interface de gestion du module dans l'onglet Administration > Journal des événements. Des traces sont aussi accessibles dans la console de JCMS.

1.2 Paramétrage d'un module

Certains modules nécessitent un paramétrage. Une partie du paramétrage peut s'effectuer dans l'interface de gestion du module en cliquant dans l'onglet Administration > Propriétés.

Screenshot

Fig. 3. Editeur de propriété d'un module.

1.3 Mise à jour d'un module

Pour mettre à jour un module, il suffit de déposer l'archive de la nouvelle version puis redémarrer le site. Les paramétrages (propriétés) de la version précédente sont préservés (dans WEB-INF/data/custom.prop). Vérifiez néanmoins dans la documentation de la nouvelle version, si de nouveaux paramétrages doivent être fait.

1.4 Suppression d'un module

Pour supprimer un module :

  1. Allez dans l'interface de gestion du module ;
  2. Cliquez sur le bouton Supprimer les fichiers déployés…;
  3. Redémarrez JCMS.

Si le module avait écrasé des fichiers lors de son installation, ceux-ci sont restaurés lors de sa suppression.

2. Principes de fonctionnement des modules

2.1 Injection de dépendances

Le gestionnaire de modules repose sur le principe de l'injection de dépendances popularisé par les frameworks tels que Spring ou PicoContainer. Ce principe à l'avantage d'assurer un couplage faible entre le module et JCMS. Ainsi, la plupart des modules peuvent être ajoutés et retirés sans avoir à modifier des fichiers de JCMS ou à compiler des classes.

Dans JCMS, l'injection de dépendance se fait en déclarant dans le fichier plugin.xml les composants du module et leur intégration dans JCMS. Lorsque JCMS doit faire un traitement ouvert aux modules, il invoque l'ensemble des composants des modules qui se sont déclarés.

Par exemple, lors de l'enregistrement d'une publication, JCMS invoque tous les DataController déclarés par les modules dans leur fichier plugin.xml. Si l'un de ces modules est retiré, les DataController associés à ce module ne seront plus invoqués lors des prochains enregistrements.

JCMS a été entièrement revu pour être extensible par ce mécanisme. Ainsi les modules peuvent intervenir dans la majeure partie de la mécanique interne de JCMS, comme par exemple :

  • Ajout de types de publication et de gabarits
  • Ajout de workflows
  • Gestion de l'authentification
  • Gestion des droits
  • Gestion des données
  • Gestion du portail
  • Gestion de l'indexation
  • Rendu des champs Wiki et Wysiwyg
  • Cycle de vie du site
  • Interfaces de JCMS

2.2 Structure d'un module

Un module est composé de l'arborescence suivante :

  • Le répertoire WEB-INF/plugins/{Name}Plugin contient les ressources internes du module
    • fichier de description plugin.xml
    • propriétés
    • autres données
  • Le répertoire plugins/{Name}Plugin/ contient les ressources publiques du modules, par exemple :
    • JSP
    • CSS, Javascript, images
    • documentation
  • Des fichiers situés dans les arborescences habituelles de JCMS, par exemple :
    • types/ : contient des gabarits des types de publication
    • WEB-INF/data/types/ : contient des types de publication
    • WEB-INF/data/workflows/ : contient des workflows
    • WEB-INF/lib/ : contient des JAR

2.3 Développement JCMS orienté module

Pour tout projet JCMS, il est recommandé de créer un module pour le projet (p. ex. Jopale Plugin pour le site Jopale).

Ce module permet d'injecter dans JCMS tous les composants Java spécifiques (DataController, QueryFilter, RightPolicy) tout en restant découplé de JCMS. La classe custom.JcmsInit ne devrait ainsi plus jamais être modifiée.

Les gabarits de types existants (gabarits de portlets, de skin…) doivent être déclarés dans le module et les JSP correspondants situés dans l'arborescence publique du module. P. ex. : plugins/{Name}Plugin/types/PortletLogin/login.jsp

Tous les fichiers spécifiques au projet (CSS, JavaScript, images, …) doivent être localisés dans l'arborescence publique du module. Il n’est cependant pas utile en l’état actuel de les déclarer dans le module. Ces fichiers spécifiques seront pris en compte par le gestionnaire des changements et inclus dans le fichier delta de la webapp. L’objectif est essentiellement de regrouper ces fichiers dans la zone du module. P. ex. : plugins/{Name}Plugin/css/fancy.css

Le fichier de suivi des changements (plugin/{Name}Plugin/docs/changelog.txt) offre un moyen simple de garder une trace de ce qui a été réalisé sur le projet.

Le système des dépendances permet de savoir précisément quels sont les autres modules indispensables au bon fonctionnement du site.

Si certains développements doivent être réutilisés dans d'autres sites JCMS (p. ex. des portlets, des skins, un système d'authentification, …), il est recommandé d'en faire des modules à part entière, distincts du module du projet. Si vous jugez qu'ils peuvent intéresser d'autres utilisateurs vous pouvez les partager à la communauté JCMS en les diffusant sur JaliosXperience (cf. section 3.5, pour connaître la démarche à suivre).

2.4 Gestion des changements

La gestion des changements de JCMS a été adaptée pour prendre en compte les modules. Au démarrage du site, JCMS signe tous les modules qui ne l'ont pas encore été. Le fichier de signature du module est placé dans le répertoire WEB-INF/plugins/{Name}Plugin/signature.xml.

Lors du calcul des changements, tous les fichiers de JCMS sont signés. Les fichiers du module n'ayant pas été modifiés sont retirés de la liste. Ceux ayant été modifiés, sont listés dans une zone à part, propre au module concerné.

Une nouvelle option du gestionnaire des changements permet d'ajouter les modules à l'archive zip générée.

3. Développement d'un nouveau module

Cette section présente le développement d'un module JCMS. Nous illustrerons ces principes avec le module Demo. Pour vos propres modules, adaptez les exemples présentés en remplaçant ce nom par celui de votre module.

3.1 Cycle de développement d'un module

Le cycle de développement d'un module comprend 4 étapes :

  1. Création du module
    Cette étape consiste à générer les ressources de base nécessaires au fonctionnement du module.
  2. Développement
    Durant cette étape le développeur alimente le module de ses développements (gabarits, type de portlets, DataController, QueryFilter, …)
  3. Empaquetage
    A cette étape, tous les fichiers du module sont empaquetés dans une archive zip. Cette archive peut alors être déployée sur d'autres sites JCMS.
  4. Diffusion
    Enfin, si il s'agit d'un module à vocation générique, il peut être diffusé sur JaliosXperience

3.2 Création d'un module

La création d'un nouveau module se fait depuis JCMS en suivant la procédure suivante

  1. Allez dans le Gestionnaire de modules
  2. Dans la boîte Créer un module, entrez le libellé du module (Demo Plugin dans notre cas) et cliquez sur le bouton Créer un module
  3. Dans le formulaire de création, renseignez les champs obligatoires. Si le module a vocation à être diffusé, respectez ces règles :
    • Le libellé du module doit être unique. Vérifiez sur JaliosXperience que le libellé n'est pas déjà utilisé.
    • Le libellé est multi-langue et devrait être renseigné au moins en anglais et en français.
    • Le nom interne du module devrait être suffixé par Plugin (e.g. BlogPlugin, PodcastPlugin, …) Le nom interne du module est construit à partir du libellé de la langue principale.
  4. Cliquez sur le bouton Enregistrer
  5. L'ossature du module est générée avec un ensemble de fichiers par défaut
  6. Cliquez sur le bouton Redémarrer… pour prendre en compte le module

3.3 Développement du module

3.3.1 Organisation des fichiers

A la création du module, l'arborescence suivante a été produite :

Fichier Description
WEB-INF/plugins/DemoPlugin/plugin.xml Le descripteur du module
WEB-INF/plugins/DemoPlugin/properties/
plugin.prop
languages/en.prop
languages/fr.prop

Les fichiers de propriétés (vides)

plugins/DemoPlugin/css/plugin.css Un fichier CSS (vide)
plugins/DemoPlugin/js/plugin.js Un fichier JavaScript (vide)
plugins/DemoPlugin/docs/index.html La documentation (à compléter)
plugins/DemoPlugin/docs/changelog.txt Le fichier des changements (vide)
plugins/DemoPlugin/docs/license.txt La licence LGPL
plugins/DemoPlugin/docs/images/icon.gif L'icône du module (16x16)
plugins/DemoPlugin/docs/images/preview.jpg L'image de prévisualisation (200x150)

Le module est maintenant prêt à accueillir de nouveaux fichiers. Tout fichier ajouté doit être déclaré dans le descripteur plugin.xml. A chaque modification du fichier plugin.xml, concernant le branchement d'un composant ou d'une target, le site JCMS doit être redémarré pour que la modification soit effective.

3.3.2 Propriétés

Un module peut utiliser des propriétés spécifiques. Ces propriétés surchargent les propriétés de jcms.prop et sont elles-même surchargées par celles de custom.prop et webapp.prop.

Les propriétés de JCMS et de tous les modules étant gérées ensemble, il est recommandé de préfixer ces propriétés par jcmsplugin.demo.* pour les différencier les unes des autres.

On distingue 2 types de propriétés :

  • Les propriétés de configuration, qui doivent être placées dans le fichier WEB-INF/plugins/DemoPlugin/properties/plugin.prop.
  • Les propriétés d'internationalisation, qui doivent être placées dans les fichiers WEB-INF/plugins/DemoPlugin/properties/languages/<lang>.prop. où <lang> représente le code de langue sur 2 caractères (e.g. fr, en, de, …). Ces propriétés ne doivent pas être préfixées par langue.

Il est possible de rendre une propriété de configuration éditable par l'utilisateur dans la zone Administration > Propriétés de l'interface de gestion du module. Pour cela, il suffit que cette propriété soit à la fois déclarée dans le fichier WEB-INF/plugins/DemoPlugin/properties/plugin.prop et dans les propriétés d'internationalisation. Les propriétés ainsi éditées par l'utilisateur sont enregistrées dans WEB-INF/data/custom.prop.

Exemples :

# WEB-INF/plugins/DemoPlugin/properties/plugin.prop
# A simple property
jcmsplugin.demo.id: 12345

# An editable property (without default value)
jcmsplugin.demo.secret-key:
# WEB-INF/plugins/DemoPlugin/properties/languages/fr.prop
# A simple language property
jcmsplugin.demo.about: A propos de Demo

# Label for editable properties
jcmsplugin.demo.secret-key: Votre clé secrète
# WEB-INF/plugins/DemoPlugin/properties/languages/en.prop
# A simple language property
jcmsplugin.demo.about: About Demo

# Label for editable properties
jcmsplugin.demo.secret-key: Your Secret Key

Les propriétés de langue peuvent être utilisées dans les JSP avec la méthode glp(prop) et dans du code Java avec les méthodes jcmsContext.glp(prop) ou JcmsUtil.glp(lang, prop)

Exemple :

<%= glp("jcmsplugin.demo.about") %>

jcmsContext.glp("jcmsplugin.demo.about");

JcmsUtil.glp(userLang, "jcmsplugin.demo.about");

Pour des interfaces d'administration plus évoluées, il est possible de redéfinir le contenu de l'onglet Administration > Propriétés (custom/doEditProperties.jsp) et même de rajouter un nouvel onglet (custom/admin.jsp).

3.3.3 Journalisation (logs)

Un module peut journaliser des événements en utilisant l'API fournie par JCMS et qui se base sur log4j. L'article JCMS 5 : La journalisation des évènements avec log4j détaille l'utilisation de cette API.

Normalement, l’utilisation de log4j nécessite une déclaration dans le fichier log4j.xml. Pour éviter d’avoir à modifier ce fichier après chaque installation de module, le gestionnaire de module fournit automatiquement un logger déjà déclaré, et ceci pour chaque module.

Un composant de module est alors en mesure de récupérer ce logger et de l’invoquer sans que l’utilisateur final du module ait besoin de modifier le fichier log4j.xml. Consultez la section 5.1 pour plus d’information.

3.4 Empaquetage

Si vous n’envisagez pas de diffuser votre module, l'empaquetage est une étape optionnelle. Elle consiste à générer l'archive zip contenant l'ensemble des ressources composant le module. Il faut veiller à ce que tous les fichiers nécessaires au module aient été correctement référencés dans le fichier plugin.xml.

L'empaquetage se fait depuis l'interface de gestion du module dans l'onglet Paquetage en cliquant sur le bouton Empaqueter… Une nouvelle archive est alors générée et apparaît dans la liste des archives disponibles pour ce module. Le numéro de version du module est concaténé au nom de l'archive (p. ex. DemoPlugin_1.0.zip).

Durant l'empaquetage, les classes Java référencées par le module sont empaquetées dans le fichier DemoPlugin.jar. Si l'option Inclure les sources Java est cochée, les sources Java sont également ajoutées dans ce fichier.

3.5 Diffusion du module

La diffusion du module est une étape optionnelle réservée aux modules ayant un caractère suffisamment générique pour être réutilisés dans d'autres applications JCMS.

Si vous souhaitez diffuser votre module sur le site de JaliosXperience, contactez l'équipe de JaliosXperience (plugins@jalios.com) qui validera sa diffusion.

4. Le descripteur plugin.xml

Le fichier plugin.xml généré contient les informations renseignées lors de la création du module.

Le but de ce descripteur est triple :

  1. Il décrit le module (nom, description, version, …) ;
  2. Il permet de d'ajouter dynamiquement des comportements à JCMS (branchement de composant ou de target) ;
  3. Il liste de façon exhaustive tous les fichiers qui composent le module afin de permettre son empaquetage.

Avec JCMS 5.7.0, fichier plugin.xml doit respecter la DTD JCMS-PLUGIN 1.0 disponible à l'URL suivante :

http://support.jalios.com/dtd/jcms-plugin-1.0.dtd

Avec JCMS 5.7.1, les modules doivents respecter la DTD JCMS-PLUGIN 1.1 disponible à l'URL suivante :

http://support.jalios.com/dtd/jcms-plugin-1.1.dtd

à partir de JCMS 5.7.2, les modules doivents respecter la DTD JCMS-PLUGIN 1.2 disponible à l'URL suivante :

http://support.jalios.com/dtd/jcms-plugin-1.2.dtd

4.1 La balise <plugin>

La balise <plugin> est la balise racine du descripteur. Elle comprend les attributs suivants :

Attribut Rôle
name Le nom du module doit être unique
version

La version du module.

Le format des versions est libre. Vous pouvez néanmoins suivre ces recommandations :

  • 0.x pour les versions alpha
  • x.0 pour les versions stables ou beta
  • 1.1, 1.2, 1.3 pour les versions mineurs
  • 1.1.1, 1.1.2 pour les versions correctives

Les changements entre les versions doivent être décrits dans le fichier docs/changelog.txt

author L'auteur du module (personne morale ou physique)
url L'URL du module (si le module est diffusé)
license

Licence du module.

Si un fichier de licence accompagne le module, il doit se situer dans plugins/DemoPlugin/docs/license.txt.

initialize Indique si le module est actif ou non
jcms

Indique les versions de JCMS avec lesquels le module est compatible.

Ne pas renseigner si le module n'est pas adhérent à une version particulière de JCMS.

Le format est une expression régulière. P. ex. : 5\.7\.0

jsync Indique si le module est compatible avec JSync. Si ce n'est pas le cas, le module ne sera pas démarré si JSync est actif.
appserver

Indique les serveurs d'application avec lesquels le module est compatible.

Le format est une expression régulière. P. ex. : (tomcat)|(webpshere)

order Indique l'ordre de parcours des modules.

Exemple :

<plugin name="DemoPlugin" 
version="1.0"
author="Demo Team"
license="LGPL"
initialize="true"
url="http://support.jalios.com/plugin/demoplugin"
jsync="true">

4.2 Information sur le module

4.2.1 La balise <label>

La balise multilingue <label> contient le libellé du module.

Exemple :

<label xml:lang="en">Demo Plug-in</label>
<label xml:lang="fr">Module Demo</label>

4.2.2 La balise <description>

La balise multilingue <description> contient la description du module.

Exemple :

<description xml:lang="en">This plugin contains …</description>
<description xml:lang="fr">Ce module contient …</description>

4.2.3 La balise <dependencies>

La balise <dependencies> liste les autres modules dont dépend ce module. Ces modules doivent être présents, déployés et initialisés. L'ordre d'initialisation des modules est fonction des dépendances.

Exemple :

<dependencies>
<dependency name="DublinCorePlugin" />
<dependency name="SquareSkinPlugin" />
<dependency name="BlogPlugin" />
<dependency name="CommentPlugin" />
</dependencies>

4.3 Gabarits et Types

La balise <types> permet de déclarer de nouveaux types mais aussi de nouveaux gabarits pour des types existants.

4.3.1 Déclaration de nouveaux types de publication

La balise <type> permet de déclarer de nouveaux types avec leurs gabarits. L'attribut name indique le nom du type et les balises <file> renseignent la liste des JSP retravaillées au travers de l'attribut path (chemin relatif au répertoire types/MyType).

Les fichiers de description XML (MyType.xml et MyType-template.xml) doivent se trouver comme habituellement dans le répertoire WEB-INF/data/types/MyType/.

Si le module a vocation à être diffusé, il est important de faire attention au nom du type afin d'éviter des conflits avec d'autres modules.

Si il s'agit d'un nouveau type de portlet, il convient de respecter le nommage en vigueur dans JCMS, en préfixant le type par "Portlet ", p. ex. "Portlet Web Mail".

Exemple :

<types>
<type name="PortletWebMail">
<file path="doPortletWebMailFullDisplay.jsp" />
</type>
</types>

Exemple de modules intégrant de nouveaux types :

  • Module Blog : ajout des types Blog et Blog Post ;
  • Module Commentaire : ajout du type Commentaire ;
  • Module Portlet Nuage : ajout du type Portlet Nuage ;
  • Module Portlet Widget : ajout du type Portlet Widget ;
  • Module Portlet Google Talk : ajout du type Portlet Google Talk ;
  • Module Podcast : ajout du type Podcast.

4.3.2 Ajout de gabarits pour des types existants

La balise <template> permet de déclarer ou de surcharger les gabarits de types JCMS existants. La syntaxe est similaire à celle générée dans les fichiers WEB-INF/data/types/MyType-templates.xml. L'attribut type indique sur quel type de publication porte le nouveau gabarit.

Il est possible de déclarer des gabarits d'affichage détaillé (FullDisplay) en utilisant la balise <displayTemplate> et des gabarits d'affichage synthétique (ResultDisplay) en utilisant la balise <queryTemplate>.

Dans les deux cas, l'attribut name doit être unique. Ceci est d'autant plus important si le module a vocation à être diffusé. Il est recommandé de préfixer cet attribut par le nom du module suivi du nom du gabarit, par exemple demo.skin.

Par défaut, la JSP du gabarit doit se trouver dans le répertoire plugins/DemoPlugin/types/MyType/. Mais il est aussi possible de placer la JSP dans le répertoire types/MyType et, dans ce cas, il faut ajouter l'attribut dir="type".

L'ajout de gabarit peut aussi servir pour remplacer des gabarits existants en utilisant le même attribut name.

Exemple :

<types>
<templates type="AbstractPortletSkinable">
<displayTemplate name="demo.skin" file="demoSkin.jsp">
<label xml:lang="en">Demo Skin</label>
<label xml:lang="fr">Habillage Demo</label>
</displayTemplate>
</templates>
</types>

Exemple de modules ajoutant de nouveaux gabarits :

  • Module Nature Blog : ajout d'un gabarit pour le type Blog ;
  • Module SquareSkin : ajout de gabarits pour le type AbstractPortletSkinable ;
  • Module GoogleSearch : ajout d'un gabarit de recherche pour le type WebPage ;
  • Module Podcast : ajout d'un gabarit pour type Portlet Requête/Itération.

4.4 Workflows

La balise <workflow> permet de déclarer de nouveaux workflows pour JCMS. Les fichiers XML de description des workflows doivent être placés dans le répertoire WEB-INF/data/workflows/. L'identifiant de workflow doit être unique.

Exemple :

<workflows>
<workflow id="wfdemo" />
</workflows>

4.5 Composants

Les composants (plugin component) sont des classes Java qui respectent l'API JCMS et s'intègrent dans la mécanique de JCMS afin de la compléter ou d'en changer le comportement. Il s'agit par exemple des DataController, StoreListener, QueryFilter, RightPolicyFilter, …

Tous les composants doivent être déclarés au sein de la balise <plugincomponent>. Les classes ainsi renseignées ne doivent pas être déclarées dans la balise <java-classes> qui est réservée pour les autres classes du module.

4.5.1 L'interface PluginComponent

Pour être pris en charge par le gestionnaire de module, un composant doit dériver de la classe JCMS correspondant à son traitement et implémenter l'interface PluginComponent.

L'interface PluginComponent impose d'implémenter la méthode init(Plugin) qui est invoquée lors du chargement du module. Le module peut y faire des initialisations et doit retourner un booléen indiquant si le module doit être activé ou non. Ceci permet par exemple de désactiver un module si certaines conditions ne sont pas remplies.

Exemple :

public class MyDataController extends BasicDataController
                              implements PluginComponent {

// ----------------------------------
// PluginComponent implementation
// ----------------------------------
public void init(Plugin plugin) { String key = channel.getProperty("jcmsplugin.demo.very-important-key"); return Util.notEmpty(key)); } // ---------------------------------- // DataController implementation // ---------------------------------- public ControllerStatus checkIntegrity(Data data) { ... } }

Si un composant fait des traitements sur des propriétés, il peut implémenter l'interface JPropertiesListener pour être notifié des mises à jour des propriétés et effectuer les rafraîchissements nécessaires.

L'ordre de parcours des modules n'influence pas l'ordre d'appel des composants car les composants ont leur propre notion d'ordre.

Les sections ci-dessous décrivent l'ensemble des composants disponibles.

4.5.2 DataController

Un DataController permet d'intervenir lors des créations, modifications, ou suppressions de données JCMS. Il permet de valider les champs soumis voire de les modifier. Pour plus de détails sur les DataController, consultez l'article JCMS 5.7 : Développer avec DCM et les DataController.

Déclaration :

<datacontroller class="..." types="..." />

avec :

Attribut Rôle
class La classe du DataController
types Liste des types de données à contrôler séparés par des pipes (|).

Exemple de déclaration :

<plugincomponents>
...
<datacontroller class="org.demo.jcmsplugin.demo.MyDataController"
types="Member|Article|PortletSearch" />
...
</plugincomponents>

Exemple de modules utilisant ce type de composant :

  • Module Blog : contrôle des soumissions.
  • Module JPoint : contrôle des transactions.

4.5.3 StoreListener

Un StoreListener permet d'être notifié des écritures sur les données de JCMS. Contrairement au DataController :

  • Il ne permet ni de valider une donnée ni de la modifier car il intervient après l'écriture.
  • Il peut être invoqué à la lecture du store (p. ex. pour gérer un index)
  • Il peut être invoqué sur tous les réplicas d'un cluster JSync ou uniquement sur celui sur lequel à lieu l'écriture.

Déclaration :

<storelistener class="..." types="…" beforeStoreLoad="..." repeat="..." />

avec :

Attribut Rôle
class La classe du StoreListener
types Liste des types de données à écouter séparés par des pipes (|).
beforeStoreLoad Indique si le StoreListener doit être appelé au chargement du Store
repeat Indique si le StoreListener doit être appelé sur tous les réplicas (true) ou uniquement sur celui ayant provoqué l'écriture (false).

Dans un environnement répliqué avec JSync, si le StoreListener doit être déclenché que sur un seul réplica (p. ex. envoi d'un mail) il est recommandé que ce soit sur le leader. Dans ce cas, on positionnera l'attribut repeat à true et on testera dans le StoreListener la méthode channel.isMainLeader().

Exemple de déclaration :

<plugincomponents>
...
<storelistener class="org.demo.jcmsplugin.demo.MyStoreListener"
types="Member|Article|PortletSearch"
beforeStoreLoad="false"
repeat="true" />
...
</plugincomponents>

Exemple de modules utilisant ce type de composant :

  • Module Category Right : invalidation de cache lors des mises à jour de publication ou de catégorie.

4.5.4 AuthenticationHandler

Un AuthenticationHandler permet d'intervenir dans la mécanique d'authentification. L'article JCMS 5.7 : Authentifications spécifiques avec les AuthenticationHandler détaille le développement des AuthenticationHandler.

Déclaration :

<authenticationhandler class="..." />

avec :

Attribut Rôle
class La classe du AuthenticationHandler

Exemple de déclaration :

<plugincomponents>
...
<authenticationhandler class=" org.demo.jcmsplugin.demo.MyAuthenticationHandler" />
...
</plugincomponents>

Exemple de modules utilisant ce type de composant :

  • Module SSO NTLM : authentification basée sur le protocole NTLM
  • Module SSO ClearTrust : authentification basée sur les jetons ClearTrust
  • Module Dev Tools : authentification administrateur pour les développeurs

4.5.5 QueryFilter

Un QueryListener permet d'intervenir dans les traitements liés aux recherches JCMS. L'article JCMS 5.7 : Développement de recherches étendues avec l’API des QueryFilter détaille le fonctionnement des QueryFilter.

Déclaration :

<queryfilter class="..." />

avec :

Attribut Rôle
class La classe du QueryFilter

Exemple de déclaration :

<plugincomponents>
...
<queryfilter class="org.demo.jcmsplugin.demo.MyQueryFilter" />
...
</plugincomponents>

Exemple de modules utilisant ce type de composant :

  • Module Google Search : QueryFilter ouvrant la recherche à Google

4.5.6 ChannelListener

Un ChannelListener permet d'intervenir dans le cycle de vie d'un site JCMS. Il permet entre autre de déclencher des traitements avant et après le chargement du store et lorsque le site JCMS est arrêté ou redémarré.

C'est par exemple, dans la méthode initAfterStoreLoad() d'un ChannelListener qu'il est possible de générer des données (cf. section 5.2) ou d'enclencher des alarmes JDring (cf. l'article JCMS 5.7 : Programmation d’alarmes et de tâches planifiées avec l’API JDring.

Déclaration :

<channellistener class="..." />

avec :

Attribut Rôle
class La classe du ChannelListener

Exemple de déclaration :

<plugincomponents>
...
<channellistener class="org.demo.jcmsplugin.demo.MyChannelListener" />
...
</plugincomponents>

Exemple de modules utilisant ce type de composant :

  • Module Podcast : génère une nouvelle branche de catégories après le chargement du store

4.5.7 CleanFilter

Un CleanFilter permet d'intervenir dans la mécanique de nettoyage du store en ajoutant de nouvelles règles de filtrage.

Déclaration :

<cleanfilter class="..." />

avec :

Attribut Rôle
class La classe du CleanFilter

Exemple de déclaration :

<plugincomponents>
...
<cleanfilter class="org.demo.jcmsplugin.demo.MyCleanFilter" />
...
</plugincomponents>

4.5.8 PolicyFilter

La balise <policyfilter> permet de déclarer des composants de type PolicyFilter. Il s'agit de classes permettant de modifier le comportement standard de JCMS (politique de droit, d'affichage du portail, …)

Déclaration :

<policyfilter class="..." />

avec :

Attribut Rôle
class La classe du PolicyFilter

Exemple de déclaration :

<plugincomponents>
...
<policyfilter class="org.demo.jcmsplugin.demo.MyRightPolicyFilter" />
...
</plugincomponents>

Pour écrire une classe PolicyFilter, il est recommandé de dériver de la classe BasicPolicyFilter correspondant (par exemple, BasicRightPolicyFilter). Cette classe implémente par défaut toutes les méthodes disponibles.

Si une même classe doit implémenter plusieurs PolicyFilter, il faut alors implémenter les interfaces PolicyFilter correspondant.

4.5.8.1 RightPolicyFilter

La classe RightPolicyFilter permet d'intervenir dans le contrôle des droits d'accès sur les publications et les catégories, sur le dépôt de fichier (upload) et sur la validation du contenu HTML des champs wysiwyg.

L'article JCMS 5.7 : Personnalisation de la gestion des droits explique la mise en œuvre de RightPolicyFilter.

Exemple d'usages :

  • Réduire la visibilité des contenus aux droits des catégories
  • Test antivirus des fichiers déposés
  • Sécurité renforcée sur les champs HTML

Exemple de modules utilisant ce type de composant :

  • Module Category Rights : droits d'accès des publications basés sur ceux des catégories
4.5.8.2 PortalPolicyFilter

La classe PortalPolicyFilter permet d'intervenir dans la mécanique du portail. Elle permet ainsi d'agir sur :

  • L'algorithme de détermination d'un portail à partir des catégories d'une publication ;
  • Le contexte de navigation (portail, catégorie courante, catégorie portail, ...) ;
  • Les redirection produites par les Portlet Redirection ;
  • La génération des liens permanents ;
  • La génération des URL descriptives ;
  • L'entête html (css, js, ... )
4.5.8.3 StatPolicyFilter

La classe StatPolicyFilter permet d'agir sur l'analyse du journal des accès lors de la production de rapport de statistique. Elle permet entre autre de modifier un StatListener ou de filtrer les StatEntry.

Exemple d'usages:

  • Génération de rapports dans plusieurs langues ;
  • Génération de rapports dans différents formats (p. ex. XML, CSV, …) ;
  • Croisement des données ;
  • Filtrage des données.
4.5.8.4 WikiPolicyFilter

La classe WikiPolicyFilter permet d'agir sur les rendus des champs Wiki. Elle est appelée avant et après le rendu.

Exemple d'usages:

  • Prise en charge de nouvelles balises ;
  • Nettoyage du contenu.
4.5.8.5 WysiwygPolicyFilter

La classe WysiwygPolicyFilter permet d'agir sur les rendus des champs texte riche (wysiwyg). Elle est appelée avant et après le rendu. Elle peut aussi agir sur les CSS associés au champ Wysiwyg.

Exemple d'usages:

  • Prise en charge de nouvelle balise ;
  • Nettoyage du contenu.

Exemple de modules utilisant ce type de composant :

  • Module Boutons TinyMCE : ajout d'une marque de troncature pour l'affichage résumé d'un champ Wysiwyg.
4.5.8.6 TemplatePolicyFilter

La classe TemplatePolicyFilter permet de choisir les gabarits à utiliser pour :

  • L'affichage détaillé ;
  • L'affichage synthétique ;
  • Les formulaires d'édition.

Elle permet aussi de :

  • Modifier les classes et les styles CSS générés pour une portlet ;
  • Modifier la liste des fichiers de CSS proposés pour un portail ;
  • Ajouter des conditions d'affichage de portlet.

Exemple d'usages:

  • Utiliser un gabarit d'édition front-office spécifique ;
  • Modifier l'affichage de résultats dans un portail donné ;
  • Ajouter un style CSS à un ensemble de portlets.

Exemple de modules utilisant ce type de composant :

  • Module Blog : formulaire d'édition front-office
4.5.8.7 ThumbnailPolicyFilter

La classe ThumbnailPolicyFilter permet d'intervenir dans la génération des vignettes associées à un document ou une URL.

Exemple d'usages :

  • Générer des vignettes pour de nouveau type de document (p. ex. vidéos, son, …) ;
  • Changer le taux/algorithme de compression ;
  • Changer les dimensions des vignettes (p. ex. vignettes carrées).
4.5.8.8 CtxMenuPolicyFilter

La classe CtxMenuPolicyFilter permet d'intervenir dans la génération des menus contextuels (des publications, des catégories et des membres). On peut ainsi ajouter ou supprimer des éléments du menu ou changer l'ordre des éléments.

Exemple d'usages :

  • Ajouts de méta-données ;
  • Ajout de lien direct vers des interfaces du back office ;
  • Ajout d'actions.
4.5.8.9 WidgetPolicyFilter

La classe WidgetPolicyFilter permet d'intervenir dans la génération des champs des formulaires de JCMS. On peut ainsi

  • Ajouter ou supprimer des actions de widget ;
  • Ajouter ou suppression des classes CSS ;
  • Ajouter des informations aux noeuds des arbres des catégories.
4.5.8.10 LuceneSearchEnginePolicyFilter

La classe LuceneSearchEnginePolicyFilter permet d'agir sur l'indexation des contenus :

  • Modifier le poids d'indexation
    • d'une catégorie
    • d'une publication,
    • d'un champs de catégorie ou publication
  • Changer de Lucene Analyzer
  • Ajouter des méta-données d'indexation pour une catégorie ou publication

Exemple d'usages :

  • Baisser le poids des messages de forum (bruits/pertinence)
  • Indexer les méta-données des pièces jointes
4.5.8.11 ChannelPolicyFilter

La classe ChannelPolicyFilter permet d'ajouter ou de modifier les méta-templates utilisés pour la générations de ressources associées aux types de publication (classe Java, JSP d'édition, d'affichage, …)

Exemple d'usages :

  • Génération de JSP d'affichage pour appareil mobile
  • Génération de web services
  • Génération de classes et méthodes utilitaires (Comparator, DataSelector, …)
4.5.8.12 WebdavPolicyFilter

La classe WebdavPolicyFilter permet d'intervenir dans le traitement des requêtes WebDA.

Exemple d'usages :

  • Filtrer les ressources à afficher
  • Ajouter ou modifier les propriétés WebDAV d'une ressource
  • Ajouter ou modifier les entêtes HTTP WebDAV (versions, service, cache, ...)
4.5.8.13 PluginPolicyFilter

La classe PluginPolicyFilter permet d'intervenir dans le cycle de vie des modules : initialisation, déploiement et suppression.

Exemple d'usages :

  • Effectuer une désinstallation plus fine d'un module
  • Compléter le déploiement d'un module

4.6 Classes et bibliothèque Java

4.6.1 Bibliothèque Java

La balise <jars> permet de déclarer de nouvelles bibliothèques Java. Les bibliothèques doivent être au format jar et localisées dans le répertoire WEB-INF/lib/.

Exemple de déclaration :

<jars>
...
<jar path="mylib.jar" />
…...
</jars>

Attention ! Toutes les classes java d'un module sont empaquetées dans un fichier JAR lors de l'empaquetage d'un module. Ce JAR ne doit pas être déclaré dans la balise <jars>.

L'utilisation de bibliothèques Java augmente le risque de conflit avec d'autres modules qui utiliserait ces mêmes bibliothèques avec un nom différent (p. ex. mylib.jar ou mylib-1.0.jar) ou dans des versions différentes (p. ex. mylib-1.0.jar ou mylib-2.0.jar). Si le module doit être diffusé, il convient de préciser l'ensemble des bibliothèques ajoutées dans la documentation.

Si vous produisez différents modules qui utilisent une même bibliothèque Java, une solution consiste à l'empaqueter dans un module distinct et à déclarer ce module dans les dépendances des autres modules.

4.6.2 Classes Java

La balise <java-classes> permet de déclarer des classes Java fournies par le module. Les classes déclarées comme composant (cf. section 4.5) comme par exemple les DataController ne doivent pas être déclarées dans la balise <java-classes>.

Attention ! Les inner classes ne sont pas prises en compte et ne sont pas empaquetées. Il est donc recommandé de ne pas développer d'inner classes ou de classes anonymes dans un module qui doit être empaqueté (cette limitation devrait être levée dans les prochaines versions de JCMS).

Exemple de déclaration:

<java-classes>
...
<java class="org.demo.jcmsplugin.demo.DemoUtil" />
...
</java-classes>

4.7 Autres ressources

Tous les fichiers qui composent le module et qui n'ont pas été déclarés dans les précédentes balises, doivent être déclarés dans les ressources publiques, dans les ressources privées ou dans les ressources de la webapp.

4.7.1 Ressources publiques

La balise <public-file> décrit tous les fichiers se trouvant dans le répertoire public du module (plugins/DemoPlugin/). Il est recommandé de décomposer ce répertoire en sous répertoires typés (images/ pour les images, css/ pour les CSS, js/ pour les JavaScript, …)

Chaque fichier est déclaré dans une balise <file> avec l'attribut path contenant le chemin relatif au répertoire plugins/DemoPlugin.

Certains de ces fichiers ont un rôle particulier et sont exploités par l'interface de gestion du module.

Fichier Rôle
docs/images/icon.gif l'icone du module (16x16px)
docs/images/preview.jpg le visuel du module (200x150px)
docs/index.html Page d'accueil de la documentation du module
docs/changelog.txt Descriptif des changements du module
docs/license.txt Licence du module
custom/admin.jsp Surcharge l'onglet Administration du module
custom/doEditProperties.jsp Surcharge l'onglet Propriété du module

Exemple de déclaration :

<public-files>
<file path="custom.jsp" />
<file path="images/demo.gif" />
<file path="css/demo.css" />
<file path="js/demo.js" />
<file path="docs/index.html" />
<file path="docs/images/icon.gif" />
<file path="docs/images/preview.jpg" />
</public-files>

4.7.2 Ressources privées

La balise <private-file> décrit tous les fichiers se trouvant dans le répertoire privé du module (WEB-INF/plugins/DemoPlugin/).

Certains fichiers ont un rôle particulier:

Fichier Rôle
properties/plugin.prop Contient les fichiers de propriétés du module
properties/languages/<lang>.prop Contient les fichiers de propriétés de langue

Exemple de déclaration :

<private-files>
<file path="properties/plugin.prop" />
<file path="properties/languages/en.prop" />
<file path="properties/languages/fr.prop" />
</private-files>

4.7.3 Ressources de la webapps

La balise <webapp-file> décrit les fichiers déployés dans la webapp en dehors des zones publique et privée du module.

Exemple de déclaration :

<webapp-files>
<directory path="js/tiny_mce/plugins/Plugin" />
</webapp-files>

Exemple de module :

  • Module Bouton TinyMCE

4.8 Targets

Les targets permettent d'insérer des JSP du module dans les JSP de JCMS. L'insertion se fait par une inclusion dynamique sans modifier le code des JSP de JCMS.

La déclaration des targets se fait dans les ressources publiques en renseignant dans la balise <file> le JSP via l'attribut include. Si le JSP doit être intégré dans plusieurs targets, celles-ci doivent être séparées par des pipes (|).

Exemple de déclaration :

<public-files>
<file path="custom.jsp" include="ADMIN_HEADER_RIGHT|WORK_HEADER_RIGHT" />
</public-files>

Le module Dev Tools permet de visualiser toutes les targets disponibles dans une page.

Screenshot

Fig. 3. Affichage des targets dans l'espace d'administration.

Le tableau ci-dessous liste les targets disponibles dans JCMS 5.7.0.

Target Localisation et usage
DISPLAY_HEADER Juste après les icônes de l'entête d'affichage d'une publication.
DISPLAY_HEADER_ICON Juste après la dernière icône de l'entête d'affichage d'une publication (dans la balise <table>)
DISPLAY_FOOTER Au début du pied de page d'une publication.
EMPTY_HEADER

Dans la balise <HEAD>.

Exemples d'usage :

  • Ajout de balises <meta>
  • Ajout de scripts
  • Ajout de marqueurs d'audience

Exemple de module :

  • Module Dublin Core
  • Module Google Analytics
EMPTY_FOOTER Juste avant la balise </BODY>
EDIT_PUB_HEADER Formulaire d'édition : juste après l'appel à handler.validate().
EDIT_PUB_FOOTER Formulaire d’édition : juste après le dernier onglet (pour ajouter un nouvel onglet)
EDIT_PUB_BUTTON Formulaire d’édition : juste après les boutons (pour ajouter un nouveau bouton).
EDIT_PUB_MAINTAB

Formulaire d’édition : à la fin de l'onglet "Contenu".

Exemple de modules :

  • Module Captcha : insertion d'un captcha dans le formulaire
  • Module JPoint : insert d'un widget dans les formulaires concernés par le module
SEARCH Interface de recherche avancée FO : après le dernier onglet (pour ajouter un nouvel onglet)
SEARCH_WORK Interface de recherche avancée BO: après le dernier onglet (pour ajouter un nouvel onglet)
QUERY_HEADER Résultats de recherche FO: avant les résultats
QUERY_WORK_HEADER Résultats de recherche BO: avant les résultats
RESULTDISPLAY_HEADER Résultats de recherche FO: avant l'affichage d'un résultat (5.7.3)
RESULTDISPLAY_FOOTER Résultats de recherche FO: après l'affichage d'un résultat (5.7.3)
MEMBER_FULLDISPLAY Dans doMemberFullDisplay.jsp après les champs du membre
EDIT_MEMBER_PROFILE Formulaire d'édition du profile : juste après le dernier onglet (pour ajouter un nouvel onglet)
EDIT_MEMBER Formulaire d'édition d'un membre : juste après le dernier onglet (pour ajouter un nouvel onglet)
MEMBER_PROFILE Affichage du profile d'un membre : juste après le dernier onglet (pour ajouter un nouvel onglet)
MEMBER_PROFILE_MAINTAB Affichage du profile d'un membre : à la fin du premier onglet
DATA_REPORT

Tableau de bords : juste après le dernier onglet (pour ajouter un nouvel onglet)

Exemple d'usage :

  • Ajout de tableaux de bords spécifiques

Exemple de modules :

  • Module TopPublications : tableau de bord des publications suivies les plus consultés
ADMIN_FOOTER Dans le pied de page des pages de l'espace d'administration
ADMIN_USERS Espace d'administration > boîte Utilisateurs
ADMIN_WORK Espace d'administration > boîte Organisation
ADMIN_REPORTING

Espace d'administration > boîte Tableaux de bord

Exemple d'usage :

  • Ajout de liens vers des tableaux de bords spécifiques

Exemple de modules :

  • Module Google Analytics : ajout d'un lien vers la page du rapport Google Analytics
ADMIN_FILE Espace d'administration > boîte Fichiers
ADMIN_MONITORING Espace d'administration > boîte Supervision
ADMIN_OPERATION Espace d'administration > boîte Exploitation
ADMIN_DATAMODEL Espace d'administration > boîte Développement > Structure
ADMIN_TOOLS

Espace d'administration > boîte Développement > Outils

Exemple d'usage :

  • Ajout de liens vers des outils

Exemple de modules :

  • Module Dev Tools : ajout de liens vers différents outils pour les développeurs
ADMIN_DOCUMENTATION Espace d'administration > boîte Documentation
ADMIN_TECHDOC Espace d'administration > boîte Documentation > Documentations techniques
ADMIN_COPYRIGHTS Espace d'administration > boîte Documentation > Mentions légales
ADMIN_HEADER_LEFT Espace d'administration > partie gauche de la barre de menu
ADMIN_HEADER_RIGHT Espace d'administration > partie droite de la barre de menu
ADMIN_HEADER_MENU Espace d'administration : après le dernier menu (Développement)
ADMIN_USERS_SUBMENU Espace d'administration > partie droite de la barre de sous-menu Utilisateurs (5.7.3)
ADMIN_WORK_SUBMENU Espace d'administration > partie droite de la barre de sous-menu Organisation (5.7.3)
ADMIN_REPORTING_SUBMENU
Espace d'administration > partie droite de la barre de sous-menu Tableaux de bord (5.7.3)
ADMIN_MONITORING_SUBMENU
Espace d'administration > partie droite de la barre de sous-menu Supervision (5.7.3)
ADMIN_OPERATION_SUBMENU
Espace d'administration > partie droite de la barre de sous-menu Exploitation (5.7.3)
ADMIN_DEV_SUBMENU
Espace d'administration > partie droite de la barre de sous-menu Développement (5.7.3)
WORK_HEADER_LEFT
Espace de travail > partie gauche de la barre de menu
WORK_HEADER_RIGHT Espace de travail > partie droite de la barre de menu
WORK_HEADER_MENU Espace de travail > après le dernier menu (Développement)
WORK_CONTENT_SUBMENU
Espace de travail > partie droite de la barre de sous-menu Contenus (5.7.3)
WORK_WORKFLOW_SUBMENU
Espace de travail > partie droite de la barre de sous-menu Tâches (5.7.3)
WORK_PORTLET_SUBMENU
Espace de travail > partie droite de la barre de sous-menu Portlets (5.7.3)
WORK_FORM_SUBMENU
Espace de travail > partie droite de la barre de sous-menu Formulaires (5.7.3)
WORK_ADMIN_SUBMENU
Espace de travail > partie droite de la barre de sous-menu Administration (5.7.3)
WORKADMIN_USERS

Espace de travail > Administration : boîte Utilisateurs

Exemple de modules :

  • Module Espace de travail hierarchique : ajout d'un lien pour créer un sous-espace.
WORKADMIN_CONFIGURATION Espace de travail > Administration : boîte Configuration
WORKADMIN_REPORTING Espace de travail > Administration : boîte Tableaux de bord
WORKADMIN_EMAIL Espace de travail > Administration : boîte E-mail
WORKADMIN_DOCUMENTATION Espace de travail > Administration : boîte Documentation
INCLUDE_BEFORE_SKIN Portlet > Avant l'inclusion de l'habillage (skin)
INCLUDE_AFTER_SKIN Portlet > Après l'inclusion de l'habillage (skin)
INCLUDE_BEFORE_TEMPLATE Portlet > Avant l'inclusion du contenu de la portlet
INCLUDE_AFTER_TEMPLATE Portlet > Après l'inclusion du contenu de la portlet

Il est possible d'ajouter de nouvelles targets dans les JSP du module pour les rendre eux aussi extensibles par d'autre modules. L'ajout d'une target dans une JSP se fait en utilisant l'attribut target du tag <jalios:include>. Le nom de la target doit être unique.

Exemple :

<jalios:include target="DEMO_TARGET"/>

5. Développements avancés

5.1 Journal des événements

En utilisant la méthode plugin.getLogger(), les composants d'un module peuvent obtenir un logger déjà déclaré dans log4j par JCMS et dont la portée est limitée au module. Ces traces sont alors consultables dans la zone Administration > Journal des évènements de l'interface de gestion du module.

Exemple :

public class MyQueryFilter extends QueryFilter 
implements PluginComponent {
private Logger logger;

public boolean init(Plugin plugin) {
logger = plugin.getLogger(); logger.info("Init done."); return true; } }

5.2 Génération de données

Un module peut avoir besoin de générer des données lors de son installation. C'est par exemple le cas du module Podcast qui génère une arborescence de catégories.

Une solution consiste à utiliser un ChannelListener pour déclencher la génération de données dans la méthode initAfterStoreLoad() puis à utiliser un virtual ID pour les référencer. Les virtual IDs sont des propriétés qui contiennent des identifiants de données JCMS et qui peuvent être utilisées comme un identifiant avec l'API d'accès aux données de JCMS.

Exemple :

public class MyChannelListener extends ChannelListener implements PluginComponent {
public static final String VIRTUAL_ID = "$id.jcmsplugin.demo.cat";
public boolean init(Plugin plugin) {
return true;
}

public void initAfterStoreLoad() {
createPluginData();
}

private void createPluginData() {
// Check if data must be created
if (channel.getCategory(VIRTUAL_ID) != null) {
return;
}

// Create data
Channel channel = Channel.getChannel();
Category cat = new Category();
cat.setName("Demo root");
cat.setParent(channel.getRootCategory());
cat.performCreate(null);


// Reference this data with a virtual ID
JProperties prop = new JProperties(); prop.setProperty(VIRTUAL_ID, cat.getId()); channel.updateAndSaveProperties(prop); } ... }