FirebirdSQL logo

Écriture de plugins

Pour écrire un plugin, vous devez implémenter certaines interfaces et mettre votre implémentation dans une bibliothèque dynamique (.dll sous Windows ou .so sous Linux), qui s’appelle un module plugin ou simplement un module.Dans la plupart des cas, un seul plugin est hébergé dans une bibliothèque dynamique, mais pas nécessairement. L’une de ces interfaces, IPluginModule, est modulaire (comme son nom l’indique plus ou moins), les autres sont des plugins.De plus, chaque module de plugin doit contenir un point d’entrée spécial exporté firebird_plugin(), dont le nom est spécifié dans le fichier include/firebird/Interfaces.h comme FB_PLUGIN_ENTRY_POINT.

Dans la partie précédente, nous avons principalement décrit comment utiliser les interfaces existantes, ici l’accent sera mis sur l’implémentation des interfaces écrites par vous-même. Bien sûr, vous pouvez et devez utiliser les interfaces existantes communes pour accéder aux bases de données Firebird (déjà décrites) et quelques interfaces supplémentaires spécialement conçues pour les plugins.

Ensuite, l’exemple de plugin de chiffrement de base de données DbCrypt.cpp est activement utilisé. C’est une bonne idée de lire cet exemple pour vous faciliter la lecture du chapitre.

Mise en œuvre d’un module de plugin

Les plugins interagissent activement avec un composant spécial de Firebird appelé le gestionnaire de plugins. En particulier, le gestionnaire de plugins doit savoir quels modules de plugins ont été chargés et doit être averti si le système d’exploitation tente de décharger l’un de ces modules sans une commande explicite du gestionnaire de plugins (cela peut se produire principalement lors de l’utilisation du serveur embarqué — lorsque le programme appelle exit() ou que la bibliothèque principale de Firebird fbclient est déchargée). L’objectif principal de l’interface IPluginModule est la notification. Tout d’abord, vous devez décider comment informer Firebird que le module sera déchargé. Lorsqu’une bibliothèque dynamique est déchargée pour une raison quelconque, de nombreuses actions spécifiques au système d’exploitation sont effectuées, et certaines de ces actions peuvent être utilisées pour détecter ce fait dans le programme. Lors de l’écriture de plugins distribués avec firebird, nous utilisons toujours l’appel global de destructeur de variables. Le gros « plus » de cette méthode est qu’elle est indépendante du système d’exploitation (bien que la fonction exit() puisse également être utilisée avec succès). Mais l’utilisation d’un destructeur permet de concentrer facilement presque tout ce qui concerne la détection de déchargement dans une seule classe, tout en implémentant l’interface IPluginModule.

La mise en œuvre minimale est la suivante :

class PluginModule : public IPluginModuleImpl<PluginModule, CheckStatusWrapper>
{

private:
  IPluginManager* pluginManager;

public:
  PluginModule()
    : pluginManager(NULL)
  { }


  ~PluginModule()
  {
    if (pluginManager)
    {
      pluginManager->unregisterModule(this);
      doClean();
    }
  }

  void registerMe(IPluginManager* m)
  {
    pluginManager = m;
    pluginManager->registerModule(this);
  }

  void doClean()
  {
    pluginManager = NULL;
  }

};

Le seul membre des données est l’interface du gestionnaire de plugins IPluginManager. Il est passé à la fonction registerModule() et stocké dans une variable privée, tandis que le module est enregistré dans le gestionnaire de plugins en utilisant la méthode callModule() avec sa propre adresse comme seul paramètre. La variable pluginManager stocke non seulement un pointeur vers l’interface, mais sert également d’indicateur indiquant que le module est enregistré. Lorsque le destructeur d’un module enregistré est appelé, il avertit le gestionnaire de plugin d’un déchargement inattendu avec un appel à unregisterModule() qui passe le pointeur à lui-même. Lorsque le gestionnaire de plugins décharge le module sur une base régulière, la première chose que l’appel de la méthode doClean() est de changer l’état du module en unregistered, ce qui évite l’appel à unregisterModule().

Après avoir implémenté l’interface du plugin IPluginModule, nous sommes tombés sur la première interface nécessaire pour implémenter les plugins – IPluginManager. Il sera activement utilisé plus tard, il est peu probable que vous ayez besoin du reste des membres de cette classe après l’avoir copié dans votre programme. N’oubliez pas de déclarer une variable globale de ce type et d’appeler la fonction registerMe() à partir de FB_PLUGIN_ENTRY_POINT.