Plugins are the primary way to extend the functionality of a DataForge Context. They provide runtime features, services, and configurations that can be shared across different tasks executed within a context.
A plugin in DataForge is defined by the Plugin interface. Every plugin must have:
- A
PluginTag: Contains thename,group, andversionof the plugin. - A
Metaconfiguration: Allows the plugin to be configured. - A reference to the
Contextit is attached to (viaContextAware).
public interface Plugin : Named, ContextAware, Provider, MetaRepr {
public val tag: PluginTag
public val meta: Meta
public fun dependsOn(): Map<PluginFactory<*>, Meta>
public fun attach(context: Context)
public fun detach()
public val isAttached: Boolean
// ...
}The lifecycle of a plugin consists of the following stages:
- Create: The plugin instance is created and configured, usually via a
PluginFactory. - Attach: The plugin is attached to a
Context. This is when the plugin can register its services in the context and initialize itself. Theattach(context)method is called by thePluginManager. - Detach: The plugin is removed from the
Context. It should clean up any resources and registrations. - Destroy: The plugin instance is discarded.
Plugins are identified by a PluginTag, which consists of:
name: The unique name of the plugin within its group.group: (Optional) The organization or project the plugin belongs to.version: (Optional) The version of the plugin. Version could be used for remote plugin management and for consistent result storage.
The PluginManager uses these tags to find and manage plugins, ensuring that no two plugins with the same tag are loaded into the same context.
Plugins can declare dependencies on other plugins. Before a plugin is attached, all its dependencies must be present and attached to the context (or its parents).
In AbstractPlugin, dependencies are declared using the require function:
class MyPlugin(meta: Meta) : AbstractPlugin(meta) {
// Declares a dependency on AnotherPlugin
val anotherPlugin by require(AnotherPluginFactory)
}The require function returns a delegate that lazily fetches the dependent plugin from the context once the plugin is attached.
Each Context has a PluginManager that:
- Stores attached plugins.
- Manages the plugin lifecycle.
- Handles plugin lookups (including searching in parent contexts).
Plugins are typically created using a PluginFactory. This allows the framework to instantiate plugins dynamically based on metadata or explicit requests. Also it allows using type-safe reference to plugins via their types and dependency injection.
public interface PluginFactory<T : Plugin> : Factory<T> {
public val tag: PluginTag
override fun build(context: Context, meta: Meta): T
}