Construire une extension

Aperçu du fonctionnement

Une extension doit se présenter sous la forme d’un ou plusieurs fichiers .jar qui sont placés dans le répertoire d’extension de l’application. Au moment de l’initialisation, l’application balaie les fichiers .jar présents à la recherche de classes implémentant l’interface fr.exemole.bdfserver.api.BdfExtensionInitializer. Pour chacune de ces classes, l’application crèe une instance (la classe en question doit disposer d’un constructeur public sans argument) qu’il va interroger pour récupérer toutes les informations nécessaires à l’utilisation de l’extension. L’interface fr.exemole.bdfserver.api.BdfExtensionInitializer est composée des méthodes suivantes (l’ordre de la liste est celui de l’ordre l’interrogation).

Principe des fournisseurs

L’idée des fournisseurs, c’est qu’une extension peut intervenir à plusieurs niveaux dans l’application : nouveaux types de formatage de données, nouvelles commandes et nouvelle pages mais aussi remplacement de commandes et de pages existantes ; enfin, une extension peut proposer un espace web totalement distinct avec ses propres règles (par exemple, une interface simplifiée). Une extension n’est bien sûr pas obligée d’intervenir à tous ces niveaux : elle peut ne proposer que des commandes en plus par exemple. Au moment de l’initialisation, l’application interroge donc l’extension si elle propose des fournisseurs dans tel ou tel dommaine ; cette interrogation est faite les deux méthodes initBasedefichesAPIProvider et initBdfServerAPIProvider.

initBasedefichesAPIProvider correspond aux fournisseurs qui interviennent après l’initialisation de la base de fiches, autrement dit le noyeau des données (définies par l’API du paquet BasedefichesAPI) mais avant l’initialisation du serveur complet. Il existe un seul fournisseur dans ce cas pour le moment : net.basedefiches.format.FormatterFactoryProvider) qui permet de définir de nouveaux formatages : cette définition doit être faite avant l’initialisation du serveur complet car sinon la syntaxe supplémentaire proposée par l’extension serait vue comme des erreurs de syntaxe au momemt la compilation des exports de données tabulaires.

initBdfServerAPIProvider correspond aux fournisseurs qui interviennent après l’initialisation du serveur complet. Les fournisseurs actuels sont les suivants :

fr.exemole.bdfserver.api.providers.BdfCommandProvider

Une classe implémentant cette interface permet de fournit de nouvelles commandes ou écraser des commandes existantes.

Pour comprendre son fonctionnement, il faut préciser qu’une commande est identifiée par deux éléments : le nom de son domaine d’action et son nom exact. Le domaine d’action est une manière de regrouper les commandes entre elles. Par exemple, toutes les commandes de gestion des mots-clés sont dans le domaine d’action « thesaurus ». On peut voir le domaine d’action dans les différents formulaires : c’est l’attribut @action de la balise <form>. Le nom de la commande, lui, est donné par le paramètre cmd de la requête

Par exemple, le formulaire permettant d’effectuer la commande de modification de l’idalpha d’un mot-clé va se présenter ainsi :

<form action="thesaurus" method="POST">
<input type="hidden" name="cmd" value="IdalphaChange">

Le domaine d’action est « thesaurus », la commande « IdalphaChange. On peut dire que les domaines d’action jouent le rôle d’espace de noms puisque deux commandes peuvent coexister avec le même nom dans des domaines d’action différents.

Chaque extension dispose automatiquement de son propre domaine d’action composé du préfixe ext_ suivi du nom d’enregistrement de l’extension. Par exemple, la commande de récapitulation analytique de l’extension Scarabé se présente sous cette forme :

/ext_fr-exemole-scarabe?cmd=AnalytiqueRecap

fr-exemole-scarabe est le nom d’enregistrement de l’extension Scarabé, AnalytiqueRecap est le nom de la commande.

L’interface fr.exemole.bdfserver.api.providers.BdfCommandProvider possède une seule méthode BdfCommand getBdfCommand(BdfCommandParameters bdfCommandParameters) où [c|fr.exemole.bdfserver.api.instruction.BdfCommandParameters]] fournit les paramètres nécessaires à la résolution de la commande, en particulier le nom du domaine d’action et le nom de la commande. Une classe implémentant fr.exemole.bdfserver.api.providers.BdfCommandProvider doit vérifier le nom du domaine d’action et le nom de la commande et dire s’il fournit ou non une commande (implémentation de l’interface fr.exemole.bdfserver.api.instruction.BdfCommand). S’il ne fournit pas de commande, il doit retourne nul et l’application vérifie avec le fournisseur suivant en terminant par le fournisseur par défaut de l’application (voir le code de la classe fr.exemole.bdfserver.servlets.instructions.CommandInstruction pour comprendre le mécanisme).

fr.exemole.bdfserver.api.providers.BdfHtmlProducerProvider

Une classe implémentant cette interface permet de fournit de nouvelles pages ou d’écraser des pages existantes. Son fonctionnement est analogue à celui de fr.exemole.bdfserver.api.providers.BdfCommandProvider puisque les pages en question sont celles associées aux commandes (par exemple, les pages affichant des formulaires). Comme les commandes, les pages sont identifiées avec leur nom et leur domaine d’action. Les domaines d’action sont les mêmes que ceux des commandes. Dans une requête, une page est récupérée via le paramètère page ou le paramètre page-error (paramètre qui permet de préciser une page d’erreur diférente de la page de résultat).

Ainsi le formulaire de modification de l’idalpha d’un mot-clé commence ainsi :

<form action="thesaurus" method="POST">
<input type="hidden" name="cmd" value="IdalphaChange">
<input type="hidden" name="page" value="motcle-changeform">

Ce qui se lit : la commande « IdalphaChange » dans le domaine d’action « thesaurus » avec affichage de la page « motle-changeform » dans le domaine d’action « thésaurus ».

Il est tout à fait possible d’avoir une page dans un domaine d’action différent de celui de la commande. Dans ce cas, le paramètre page est composé du nom du domaine suivi par le nom de la page séparé par une barre oblique. Pour une extension, cela permet de proposer une page différente de résultat d’un formulaire différent sans toucher à la commande elle-même et sans surcharger la page de résultat normale. Par exemple :

<form action="thesaurus" method="POST">
<input type="hidden" name="cmd" value="IdalphaChange">
<input type="hidden" name="page" value="ext_nomdextension/page-alternative">

Il s’agit toujours de la commande « IdalphaChange » du domaine d’action « thesaurus » mais la page de résultat sera la page « page-alternative » du domaine de l’extension « nomdextension ».

fr.exemole.bdfserver.api.providers.BdfJsonProducerProvider

Fonctionne exactement comme BdfHtmlProducerProvider à la différence que c’est pour produire des données de résultat au format JSON et non des pages HTML.

fr.exemole.bdfserver.api.providers.MenuLinkProvider

Permet de rajouter un groupe de liens dans le menu des actions de l’interface de saisie (la liste déroulante à côté du lien de sélection dans la barre du haut). Cela permet de donner accès facilement accès aux pages supplémentaires proposés par l’extension. Il est préférable de se limiter à deux ou trois liens.

fr.exemole.bdfserver.api.providers.BdfInstructionProvider

Ce fournisseur est celui qui fournit le plus de liberté à l’extension. En effet, il permet de faire gérer directement par l’extension tous les Urls du type :

/ext/{nom d'enregistrement de l'extension}/*

La seule méthode de ce fournisseur est : getBdfInstruction(String extensionPath, RequestMap requestMap). extensionPath désigne la chaine après /ext/{nom d'enregistrement de l'extension}/, RequestMap contient les paramètres éventuels de la requête.

À partir de là, l’extension a une liberté à peu près totale, elle peut proposer un mode alternatif d’authentification, une autre interface de saisie, des autres formats de données. On pourra par exemple l’utiliser pour un formulaire direct de saisie de fiche (sans mot de passe), la fourniture de JSON public, etc.

Le choix entre d’une combinaison entre BdfHtmlProducerProvider et BdfCommandProvider d’un côté ou BdfInstructionProvider dépendra du degré d’intégration nécessaire dans l’interface standard, sachant qu’une même extension peut très bien utiliser les deux mécanismes.

Note : si une instruction modifie les données de la base, afin d’éviter tout conflit d’édition, il faut faire une synchronisation sur l’instance unique de BdfServer fournie par BdfContext :

BdfServer bdfServer = bdfContext.getBdfServer();
synchronized(bdfServer) {
...
}