I recently started a branch that provides a uniform API for plugins to register things to different SMTK managers (currently
operation::Manager, but more to come!). The pattern I used requires the managers to be known at compile-time: a manager that has things register to it cannot be introduced to SMTK via a runtime-loadable plugin. It does not mean that all SMTK managers must be present at compile-time, though: a manager can still be disabled via a compile-time switch (much like the Qt or VTK extensions), and can be linked into a project via plugins that explicitly call it (if the plugin isn’t loaded, neither is the manager).
By requiring that managers are known at compile-time, we gain the flexibility of adding to and removing from these managers via plugins without worrying worrying about plugin load order issues and without incurring the penalty of a double-dispatch between managers and plugins (see
smtk::common::Registry for more details). Pinning down one side of the registration process simplifies the logic of registration a great deal; in this setup, we do not have to worry about a manager being introduced to a system after a plugin that would register to it, for example. A compile-time implementation also avoids the overuse of polymorphism, reducing the intellectual buy-in for creating an SMTK plugin.
As a concrete use-case, we have the
smtk::bridge::polygon session (a plugin) that registers to different managers. If you wish to create a new
smtk::foo manager and have the polygon session register to it, you could create
smtk::foo::Manager and its logic in
smtkFoo.so and either
extend (i.e. modify) the polygon session’s registration logic to include it, or
create a new plugin that brings in both
smtk::foo::Manager, the polygon session and the registration logic between the two.
In both scenarios, new code that uses both the polygon session and the new manager’s feature set would need to be written, so a link between
smtkPolygon.so will have to exist in any pattern. Determining where and how this link is made is simply bookkeeping.
One alternative to compile-time manager descriptions would be to connect managers via an abstract base class
smtk::common::Manager and “managed” things via an abstract base class
smtk::common::Managed. We would then need to construct an extensible and plugin-linktime executable set of logic for performing a double-dispatch over managers and managed elements. While performance isn’t really an issue for events that only occur at plugin load/unload, double-dispatch solutions are rarely elegant, and this approach would require an increased buy-in for plugin developers (and brings us closer to a
vtkObject-style use of polymorphism).
I am heavily biased towards compile-time solutions when I think they are appropriate, so take this all with a grain of salt. Please let me know what you think!