ImageJ2 has a flexible “extensibility framework” for managing plugins and their cousins, modules. Lately we have been making big improvements that are too numerous to mention here. But we wanted to make note of some of the progress that we made within the past couple of days. Be warned: it is very technical and will likely only be of interest to other ImageJ2 developers.
- We now have a fully working way to create plugins with dynamic numbers of input and output parameters, by extending the
DynamicPlugin
class.DynamicPluginTest
shows an example. (Feedback on the code is welcome; use ⌃ Ctrl + ⇧ Shift + T in Eclipse to Open Type and jump straight to it. To try it out in the GUI, open a couple of datasets first and then run Plugins › Sandbox › Dynamic Plugin Test. It will produce one output dataset per input, of the specified size squared.) - There is now a
ModuleService
that tracks all known modules (plugins or otherwise). It publishesModulesChangedEvent
(in the case of new modules added,ModulesAddedEvent
, and in the case of modules removed,ModulesRemovedEvent
) whenever the list of known modules changes. This is similar to theObjectService
’sObjectsUpdatedEvent
, so we expanded that to have the same hierarchy (Changed
at base,Added
andRemoved
as subtypes). - The
ObjectService
’s index was split out into its own class calledObjectIndex
, which maintains the objects on every list that is part of its type hierarchy. For example, an object of typeInteger
would be registered onto the following lists:Integer
,Number
,Object
,Serializable
,Comparable
. - We implemented a subclass of
ObjectIndex
calledSortedObjectIndex
which does the same thing, but keeps all the lists sorted. Then we subclassed that asPluginIndex
, and used it with thePluginService
. So the plugin service now keeps an index of all its plugins including supertype hierarchies, which it didn’t before. So for example, you can now ask the plugin service for allRunnablePlugins
, and getImageJPlugins
(a subtype) included in that. ModuleService
also uses aSortedObjectIndex
subclass calledModuleIndex
to maintain its list of modules.ModuleService
has run methods for executing anyModule
orModuleInfo
, with or without spawning a new thread, and with or without a specified set of pre- and postprocessors.- Similarly,
PluginService
has run methods for executing anyModule
orModuleInfo
with its knownPreprocessorPlugins
andPostprocessorPlugins
. These methods are the central way to run a module programmatically. - The
ShadowMenu
, a UI-agnostic menu tree structure, now has each leaf linked to aModuleInfo
. This means that menu entries will now be capable of running scripts and other modules, not just plugins.
What’s next:
- Dynamic plugin implementations:
- We are going to update various core plugins which need the dynamic plugin mechanism, to give it a test drive.
- Dynamic menus:
- Update
ShadowMenu
to listen toModulesChangedEvent
andModuleUpdatedEvent
and change its internal structure accordingly. This will generally entail surgical changes to its structure rather than a full menu rebuild. - Update the UI-toolkit-specific menu builders to keep the resultant menu structures (e.g.,
JMenuBar
) linked to theShadowMenu
. When theShadowMenu
publishes events indicating menu items have changed, the actual UI menu needs to automatically update to reflect that as well. - Maybe: update
ModuleService
to maintain aShadowMenu
data structure, which can be obtained for whatever purpose.
- Update
- More module invocation routines:
- It would be nice to have run methods of
ModuleService
andPluginService
that accept parameters programmatically, either as a list or as a map. Grant’sInvokePluginTest
shows what we are going for.
- It would be nice to have run methods of