|
| 1 | +# DataForge Plugin Mechanics |
| 2 | + |
| 3 | +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. |
| 4 | + |
| 5 | +## The Plugin Interface |
| 6 | + |
| 7 | +A plugin in DataForge is defined by the `Plugin` interface. Every plugin must have: |
| 8 | +- A `PluginTag`: Contains the `name`, `group`, and `version` of the plugin. |
| 9 | +- A `Meta` configuration: Allows the plugin to be configured. |
| 10 | +- A reference to the `Context` it is attached to (via `ContextAware`). |
| 11 | + |
| 12 | +```kotlin |
| 13 | +public interface Plugin : Named, ContextAware, Provider, MetaRepr { |
| 14 | + public val tag: PluginTag |
| 15 | + public val meta: Meta |
| 16 | + public fun dependsOn(): Map<PluginFactory<*>, Meta> |
| 17 | + public fun attach(context: Context) |
| 18 | + public fun detach() |
| 19 | + public val isAttached: Boolean |
| 20 | + // ... |
| 21 | +} |
| 22 | +``` |
| 23 | + |
| 24 | +## Plugin Lifecycle |
| 25 | + |
| 26 | +The lifecycle of a plugin consists of the following stages: |
| 27 | + |
| 28 | +1. **Create**: The plugin instance is created and configured, usually via a `PluginFactory`. |
| 29 | +2. **Attach**: The plugin is attached to a `Context`. This is when the plugin can register its services in the context and initialize itself. The `attach(context)` method is called by the `PluginManager`. |
| 30 | +3. **Detach**: The plugin is removed from the `Context`. It should clean up any resources and registrations. |
| 31 | +4. **Destroy**: The plugin instance is discarded. |
| 32 | + |
| 33 | +## Plugin Identification (PluginTag) |
| 34 | + |
| 35 | +Plugins are identified by a `PluginTag`, which consists of: |
| 36 | +- `name`: The unique name of the plugin within its group. |
| 37 | +- `group`: (Optional) The organization or project the plugin belongs to. |
| 38 | +- `version`: (Optional) The version of the plugin. Version could be used for remote plugin management and for consistent result storage. |
| 39 | + |
| 40 | +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. |
| 41 | + |
| 42 | +## Dependency Management |
| 43 | + |
| 44 | +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). |
| 45 | + |
| 46 | +### Declaring Dependencies |
| 47 | +In `AbstractPlugin`, dependencies are declared using the `require` function: |
| 48 | + |
| 49 | +```kotlin |
| 50 | +class MyPlugin(meta: Meta) : AbstractPlugin(meta) { |
| 51 | + // Declares a dependency on AnotherPlugin |
| 52 | + val anotherPlugin by require(AnotherPluginFactory) |
| 53 | +} |
| 54 | +``` |
| 55 | + |
| 56 | +The `require` function returns a delegate that lazily fetches the dependent plugin from the context once the plugin is attached. |
| 57 | + |
| 58 | +## Plugin Manager |
| 59 | + |
| 60 | +Each `Context` has a `PluginManager` that: |
| 61 | +- Stores attached plugins. |
| 62 | +- Manages the plugin lifecycle. |
| 63 | +- Handles plugin lookups (including searching in parent contexts). |
| 64 | + |
| 65 | +### Requesting a Plugin |
| 66 | +You can request a plugin from a context using the `request` extension function: |
| 67 | + |
| 68 | +```kotlin |
| 69 | +val myPlugin = context.request(MyPluginFactory) |
| 70 | +``` |
| 71 | + |
| 72 | +If the plugin is already present in the context or its parents, it is returned. Otherwise, a new child context is created with the requested plugin. |
| 73 | + |
| 74 | +## Plugin Factories |
| 75 | + |
| 76 | +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. |
| 77 | + |
| 78 | +```kotlin |
| 79 | +public interface PluginFactory<T : Plugin> : Factory<T> { |
| 80 | + public val tag: PluginTag |
| 81 | + override fun build(context: Context, meta: Meta): T |
| 82 | +} |
| 83 | +``` |
0 commit comments