From 3ab3f2766c724d0f2191ca158fbcb48ececaee00 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 10 Nov 2020 20:18:54 +0300 Subject: [PATCH] Add preemptive initialization for plugins --- dataforge-context/api/dataforge-context.api | 8 ++--- .../kotlin/hep/dataforge/context/Context.kt | 30 ++----------------- .../hep/dataforge/context/ContextBuilder.kt | 15 +++++----- .../hep/dataforge/context/PluginManager.kt | 18 +++++------ .../hep/dataforge/workspace/Workspace.kt | 20 ++++++------- 5 files changed, 28 insertions(+), 63 deletions(-) diff --git a/dataforge-context/api/dataforge-context.api b/dataforge-context/api/dataforge-context.api index 51349c64..39fa72d8 100644 --- a/dataforge-context/api/dataforge-context.api +++ b/dataforge-context/api/dataforge-context.api @@ -39,12 +39,11 @@ public final class hep/dataforge/context/ClassLoaderPluginKt { public class hep/dataforge/context/Context : hep/dataforge/context/Named, hep/dataforge/meta/MetaRepr, hep/dataforge/provider/Provider, kotlinx/coroutines/CoroutineScope { public static final field Companion Lhep/dataforge/context/Context$Companion; public static final field PROPERTY_TARGET Ljava/lang/String; - public fun (Lhep/dataforge/names/Name;Lhep/dataforge/context/Context;Lhep/dataforge/meta/Meta;)V - public final fun activate (Ljava/lang/Object;)V + public fun (Lhep/dataforge/names/Name;Lhep/dataforge/context/Context;Lhep/dataforge/meta/Meta;Ljava/util/Set;)V + public synthetic fun (Lhep/dataforge/names/Name;Lhep/dataforge/context/Context;Lhep/dataforge/meta/Meta;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun close ()V public fun content (Ljava/lang/String;)Ljava/util/Map; public final fun content (Ljava/lang/String;Z)Ljava/util/Map; - public final fun deactivate (Ljava/lang/Object;)V public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext; public fun getDefaultChainTarget ()Ljava/lang/String; public fun getDefaultTarget ()Ljava/lang/String; @@ -52,7 +51,6 @@ public class hep/dataforge/context/Context : hep/dataforge/context/Named, hep/da public final fun getName ()Lhep/dataforge/names/Name; public final fun getParent ()Lhep/dataforge/context/Context; public final fun getPlugins ()Lhep/dataforge/context/PluginManager; - public final fun isActive ()Z public fun toMeta ()Lhep/dataforge/meta/Meta; } @@ -152,7 +150,7 @@ public final class hep/dataforge/context/PluginFactory$Companion { } public final class hep/dataforge/context/PluginManager : hep/dataforge/context/ContextAware, java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker { - public fun (Lhep/dataforge/context/Context;)V + public fun (Lhep/dataforge/context/Context;Ljava/util/Set;)V public final fun fetch (Lhep/dataforge/context/PluginFactory;ZLhep/dataforge/meta/Meta;)Lhep/dataforge/context/Plugin; public final fun fetch (Lhep/dataforge/context/PluginFactory;ZLkotlin/jvm/functions/Function1;)Lhep/dataforge/context/Plugin; public static synthetic fun fetch$default (Lhep/dataforge/context/PluginManager;Lhep/dataforge/context/PluginFactory;ZLhep/dataforge/meta/Meta;ILjava/lang/Object;)Lhep/dataforge/context/Plugin; diff --git a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt index b675a42b..605e6f8b 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt @@ -28,6 +28,7 @@ public open class Context( final override val name: Name, public val parent: Context?, meta: Meta, + plugins: Set = emptySet(), ) : Named, MetaRepr, Provider, CoroutineScope { /** @@ -47,32 +48,7 @@ public open class Context( /** * A [PluginManager] for current context */ - public val plugins: PluginManager = PluginManager(this) - - @Deprecated("To be removed in favor of immutable plugins") - private val activators = HashSet() - - /** - * Defines if context is used in any kind of active computations. Active context properties and plugins could not be changed - */ - @Deprecated("To be removed in favor of immutable plugins") - public val isActive: Boolean = activators.isNotEmpty() - - /** - * Mark context as active and used by [activator] - */ - @Deprecated("To be removed in favor of immutable plugins") - public fun activate(activator: Any) { - activators.add(activator) - } - - /** - * Mark context unused by [activator] - */ - @Deprecated("To be removed in favor of immutable plugins") - public fun deactivate(activator: Any) { - activators.remove(activator) - } + public val plugins: PluginManager by lazy { PluginManager(this, plugins)} override val defaultTarget: String get() = Plugin.TARGET @@ -104,8 +80,6 @@ public open class Context( * Detach all plugins and terminate context */ public open fun close() { - @Suppress("DEPRECATION") - if (isActive) error("Can't close active context") //detach all plugins plugins.forEach { it.detach() } } diff --git a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/ContextBuilder.kt b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/ContextBuilder.kt index 75bd6c5d..b742474c 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/ContextBuilder.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/ContextBuilder.kt @@ -8,7 +8,7 @@ import hep.dataforge.names.toName */ @DFBuilder public class ContextBuilder(private val parent: Context = Global, public var name: String = "@anonymous") { - private val plugins = ArrayList() + private val plugins = HashSet() private var meta = MetaBuilder() public fun properties(action: MetaBuilder.() -> Unit) { @@ -20,9 +20,12 @@ public class ContextBuilder(private val parent: Context = Global, public var nam } @OptIn(DFExperimental::class) - public fun plugin(tag: PluginTag, metaBuilder: MetaBuilder.() -> Unit = {}) { - val factory = parent.gatherInSequence>(PluginFactory.TYPE).values + private fun findPluginFactory(tag: PluginTag): PluginFactory<*> = + parent.gatherInSequence>(PluginFactory.TYPE).values .find { it.tag.matches(tag) } ?: error("Can't resolve plugin factory for $tag") + + public fun plugin(tag: PluginTag, metaBuilder: MetaBuilder.() -> Unit = {}) { + val factory = findPluginFactory(tag) val plugin = factory.invoke(Meta(metaBuilder), parent) plugins.add(plugin) } @@ -36,10 +39,6 @@ public class ContextBuilder(private val parent: Context = Global, public var nam } public fun build(): Context { - return Context(name.toName(), parent, meta.seal()).apply { - this@ContextBuilder.plugins.forEach { - plugins.load(it) - } - } + return Context(name.toName(), parent, meta.seal(), plugins) } } \ No newline at end of file diff --git a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginManager.kt b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginManager.kt index cdae4f53..3e9def85 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginManager.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginManager.kt @@ -16,21 +16,24 @@ public interface PluginFactory : Factory { } } - /** * The manager for plugin system. Should monitor plugin dependencies and locks. * * @property context A context for this plugin manager * @author Alexander Nozik */ -public class PluginManager(override val context: Context) : ContextAware, Iterable { +public class PluginManager(override val context: Context, plugins: Set) : ContextAware, Iterable { //TODO refactor to read-only container /** * A set of loaded plugins */ - private val plugins = HashSet() + private val plugins: HashSet = HashSet(plugins) + + init { + plugins.forEach { it.attach(context) } + } /** * A [PluginManager] of parent context if it is present @@ -56,7 +59,6 @@ public class PluginManager(override val context: Context) : ContextAware, Iterab public fun find(inherit: Boolean = true, predicate: (Plugin) -> Boolean): Plugin? = list(inherit).find(predicate) - /** * Find a loaded plugin via its tag * @@ -66,7 +68,6 @@ public class PluginManager(override val context: Context) : ContextAware, Iterab public operator fun get(tag: PluginTag, inherit: Boolean = true): Plugin? = find(inherit) { tag.matches(it.tag) } - /** * Find a loaded plugin via its class. This method does not check if the result is unique and just returns first * plugin matching the class condition. @@ -96,10 +97,8 @@ public class PluginManager(override val context: Context) : ContextAware, Iterab * @return */ public fun load(plugin: T): T { - if (context.isActive) error("Can't load plugin into active context") - if (get(plugin::class, plugin.tag, recursive = false) != null) { - error("Plugin of type ${plugin::class} already exists in ${context.name}") + error("Plugin with tag ${plugin.tag} already exists in ${context.name}") } else { for (tag in plugin.dependsOn()) { fetch(tag, true) @@ -125,8 +124,6 @@ public class PluginManager(override val context: Context) : ContextAware, Iterab * Remove a plugin from [PluginManager] */ public fun remove(plugin: Plugin) { - if (context.isActive) error("Can't remove plugin from active context") - if (plugins.contains(plugin)) { logger.info { "Removing plugin ${plugin.name} from ${context.name}" } plugin.detach() @@ -136,7 +133,6 @@ public class PluginManager(override val context: Context) : ContextAware, Iterab /** * Get an existing plugin with given meta or load new one using provided factory - * */ public fun fetch(factory: PluginFactory, recursive: Boolean = true, meta: Meta = Meta.EMPTY): T { val loaded = get(factory.type, factory.tag, recursive) diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Workspace.kt b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Workspace.kt index b45a662c..b9aaad18 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Workspace.kt +++ b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Workspace.kt @@ -45,25 +45,23 @@ public interface Workspace : ContextAware, Provider { * Invoke a task in the workspace utilizing caching if possible */ public fun run(task: Task, config: Meta): DataNode { - context.activate(this) - try { - val model = task.build(this, config) - task.validate(model) - return task.run(this, model) - } finally { - context.deactivate(this) - } + val model = task.build(this, config) + task.validate(model) + return task.run(this, model) } public companion object { public const val TYPE: String = "workspace" - public operator fun invoke(parent: Context = Global, block: SimpleWorkspaceBuilder.() -> Unit): SimpleWorkspace = + public operator fun invoke( + parent: Context = Global, + block: SimpleWorkspaceBuilder.() -> Unit, + ): SimpleWorkspace = SimpleWorkspaceBuilder(parent).apply(block).build() } } public fun Workspace.run(task: Task<*>, target: String): DataNode { - val meta = targets[target] ?: error("A target with name $target not found in ${this}") + val meta = targets[target] ?: error("A target with name $target not found in $this") return run(task, meta) } @@ -77,5 +75,5 @@ public fun Workspace.run(task: String, meta: Meta): DataNode = public fun Workspace.run(task: String, block: MetaBuilder.() -> Unit = {}): DataNode = run(task, Meta(block)) -public fun Workspace.run(task: Task, metaBuilder: MetaBuilder.() -> Unit = {}): DataNode = +public fun Workspace.run(task: Task, metaBuilder: MetaBuilder.() -> Unit = {}): DataNode = run(task, Meta(metaBuilder)) \ No newline at end of file