Channels ▼
RSS

C/C++

Building Your Own Plugin Framework: Part 4


PluginHelper

The PluginHelper is yet another helper class that takes the drudge out of writing the plugin glue code. Listing Three is the code.

#ifndef PF_PLUGIN_HELPER_H
#define PF_PLUGIN_HELPER_H
#include "plugin.h"
#include "base.h"
class PluginHelper
{  
  struct RegisterParams : public PF_RegisterParams
  {    
    RegisterParams(PF_PluginAPI_Version v,
                         PF_CreateFunc cf,
                         PF_DestroyFunc df,
                         PF_ProgrammingLanguage pl)
    {
      version=v;
      createFunc=cf;
      destroyFunc=df;
      programmingLanguage=pl;
    }
  };  
public:
  PluginHelper(const PF_PlatformServices * params) : 
    params_(params),
    result_(exitPlugin)
  {
  }
  PF_ExitFunc getResult()
  {
    return result_;
  }  
  template <typename T>
  void registerObject(const apr_byte_t * objectType, 
                      PF_ProgrammingLanguage pl=PF_ProgrammingLanguage_C,
                      PF_PluginAPI_Version v = {1, 0})
  {
    RegisterParams rp(v, T::create, T::destroy, pl);
    apr_int32_t rc = params_->registerObject(objectType, &rp);
        if (rc < 0)
    {
      result_ = NULL;
      THROW << "Registration of object type " 
        << objectType << "failed. "
        << "Error code=" << rc;
    }
  }
private:

  static apr_int32_t exitPlugin()
  {
    return 0;
  }
private:
  const PF_PlatformServices * params_;
  PF_ExitFunc result_;
}; 
#endif // PF_PLUGIN_HELPER_H
Listing Three

It is designed to work with plugin object classes that implement the PF_CreateFunc and PF_DestroyFunc mandatory functions as static methods. That's it. No other requirements. As it happens ActorBaseTemplate satisfies this requirement so plugin object classes that derive from ActorBaseTemplate are automatically compatible with PluginHelper. The PluginHelper is designed to be used inside the mandatory PF_initPlugin() entry point. You will see it in action in the next article when I cover writing plugins. For now, I'll just go over the services PluginHelper makes available to the plugin developer. The job of the entry point function is to register all the plugin object types supported by the plugin and if successful return a function pointer to a PF_ExitFunc exit function with a particular signature. If something goes wrong it should return NULL.

The PluginHelper constructor accepts a pointer to the PF_PlatfromServices struct that contains the host system plugin API version and invokeService and registerObject function pointers and stores them. It also stores in its result member the exitPlugin function pointer that will be returned if the plugin initialization is successful.

PluginHelper provides the templated registerObject method that does most of the work. The T template parameter is the object type that you want to register. It should have a create() and destroy() static methods that conform to PF_CreateFunc and PF_DestroyFunc. It accepts an object type string and optional programming language (defaults to PF_ProgrammingLanguage_C). This method performs a version check to make sure the plugin version is compatible with the host system. If everything is fine it prepares a RegisterObjectParams struct and calls the registerObject() function and check the result. If the version check or the invocation of the registerObject function pointer fail it will report the error (this is done by the CHECK macro if the condition is false), set the result_ to NULL and swallow the exception thrown by CHECK. The reason it doesn't let the exception propagate is because PF_initPlugin (where PluginHelper is supposed to be used) is a C function that shoul not let exceptions propagate across the binary compatibility bounday. Catching all exceptions in registerObject saves the plugin developer the trouble doing it (or worse, forgetting to do it). This is a fine example of the convenience of using the THROW, CHECK, and ASSERT macros. The error message is constructed easily using the streaming operator. No need to allocate buffers, concatanate strings or use printf. The resulting reportError call will contain the exact location of the error (__FILE__, __LINE__) without having to explicitly specify it.

Typically, a plugin will register more than one object type. If any object type fails to register the result_ will be NULL. It may be okay for some object types to fail registration. For example, you may register multiple versions of the same object type and one of the versions is not supported anymore by the host system. In this case only this object type will fail to register. The plugin developer may check the value of result_ after each call to PluginHelper::registerObject() and decide if it's fatal or not. If it's a benign failure it may eventually return PluginHelper::ExitPlugin after all.

The default behavior is that every failure is fatal and the plugin developer should just return PluginHelper::getResult() that will return the value of result_, which will be PluginHelper::ExitPlugin (if all registrations succeeded) or NULL (if any registration failed).


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video