From 030f3ed6fecb5abbc6c07f631e59cfdea83c0294 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 28 Dec 2020 21:05:27 +0300 Subject: [PATCH] Refactor context factories --- CHANGELOG.md | 1 + dataforge-context/api/dataforge-context.api | 6 ++---- .../kotlin/hep/dataforge/context/Context.kt | 3 +-- .../hep/dataforge/context/ContextBuilder.kt | 19 ++++++++--------- .../hep/dataforge/context/PluginFactory.kt | 14 +++++++++++++ .../hep/dataforge/context/PluginManager.kt | 15 ++----------- .../hep/dataforge/context/ContextTest.kt | 6 +++--- dataforge-meta/api/dataforge-meta.api | 12 ----------- .../kotlin/hep/dataforge/meta/ItemProvider.kt | 12 +++++++---- .../hep/dataforge/meta/MetaWithDefault.kt | 18 ---------------- .../workspace/DataPropagationTest.kt | 5 ++--- .../workspace/SimpleWorkspaceTest.kt | 21 ++++++++++++------- 12 files changed, 56 insertions(+), 76 deletions(-) create mode 100644 dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginFactory.kt delete mode 100644 dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaWithDefault.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index a586067c..a485b761 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - \[Major breaking change\] Schemes and configurables us `MutableItemProvider` instead of `Config` - \[Major breaking change\] `MetaItem` renamed to `TypedMetaItem` and `MetaItem` is now an alias for `TypedMetaItem<*>` - \[Major breaking change\] Moved `NodeItem` and `ValueItem` to a top level +- Plugins are removed from Context constructor and added lazily in ContextBuilder ### Deprecated diff --git a/dataforge-context/api/dataforge-context.api b/dataforge-context/api/dataforge-context.api index f433949c..b8c52285 100644 --- a/dataforge-context/api/dataforge-context.api +++ b/dataforge-context/api/dataforge-context.api @@ -38,8 +38,7 @@ 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;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 (Lhep/dataforge/names/Name;Lhep/dataforge/context/Context;Lhep/dataforge/meta/Meta;)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; @@ -65,7 +64,6 @@ public final class hep/dataforge/context/ContextBuilder { public synthetic fun (Lhep/dataforge/context/Context;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun build ()Lhep/dataforge/context/Context; public final fun getName ()Ljava/lang/String; - public final fun plugin (Lhep/dataforge/context/Plugin;)V public final fun plugin (Lhep/dataforge/context/PluginFactory;Lkotlin/jvm/functions/Function1;)V public final fun plugin (Lhep/dataforge/context/PluginTag;Lkotlin/jvm/functions/Function1;)V public final fun plugin (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V @@ -147,7 +145,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;Ljava/util/Set;)V + public fun (Lhep/dataforge/context/Context;)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 9ea626e9..3ac2f7a3 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt @@ -25,7 +25,6 @@ public open class Context( final override val name: Name, public val parent: Context?, meta: Meta, - plugins: Set = emptySet(), ) : Named, MetaRepr, Provider, CoroutineScope { /** @@ -40,7 +39,7 @@ public open class Context( /** * A [PluginManager] for current context */ - public val plugins: PluginManager by lazy { PluginManager(this, plugins)} + public val plugins: PluginManager by lazy { PluginManager(this)} override val defaultTarget: String get() = Plugin.TARGET 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 b742474c..69a68026 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/ContextBuilder.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/ContextBuilder.kt @@ -8,17 +8,13 @@ import hep.dataforge.names.toName */ @DFBuilder public class ContextBuilder(private val parent: Context = Global, public var name: String = "@anonymous") { - private val plugins = HashSet() + private val factories = HashMap, Meta>() private var meta = MetaBuilder() public fun properties(action: MetaBuilder.() -> Unit) { meta.action() } - public fun plugin(plugin: Plugin) { - plugins.add(plugin) - } - @OptIn(DFExperimental::class) private fun findPluginFactory(tag: PluginTag): PluginFactory<*> = parent.gatherInSequence>(PluginFactory.TYPE).values @@ -26,12 +22,11 @@ public class ContextBuilder(private val parent: Context = Global, public var nam public fun plugin(tag: PluginTag, metaBuilder: MetaBuilder.() -> Unit = {}) { val factory = findPluginFactory(tag) - val plugin = factory.invoke(Meta(metaBuilder), parent) - plugins.add(plugin) + factories[factory] = Meta(metaBuilder) } - public fun plugin(builder: PluginFactory<*>, action: MetaBuilder.() -> Unit = {}) { - plugins.add(builder.invoke(Meta(action))) + public fun plugin(factory: PluginFactory<*>, metaBuilder: MetaBuilder.() -> Unit = {}) { + factories[factory] = Meta(metaBuilder) } public fun plugin(name: String, group: String = "", version: String = "", action: MetaBuilder.() -> Unit = {}) { @@ -39,6 +34,10 @@ public class ContextBuilder(private val parent: Context = Global, public var nam } public fun build(): Context { - return Context(name.toName(), parent, meta.seal(), plugins) + return Context(name.toName(), parent, meta.seal()).apply { + factories.forEach { (factory, meta) -> + plugins.load(factory, meta) + } + } } } \ No newline at end of file diff --git a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginFactory.kt b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginFactory.kt new file mode 100644 index 00000000..5985a1e7 --- /dev/null +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginFactory.kt @@ -0,0 +1,14 @@ +package hep.dataforge.context + +import hep.dataforge.provider.Type +import kotlin.reflect.KClass + +@Type(PluginFactory.TYPE) +public interface PluginFactory : Factory { + public val tag: PluginTag + public val type: KClass + + public companion object { + public const val TYPE: String = "pluginFactory" + } +} 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 3e9def85..6ab0f5d9 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginManager.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/PluginManager.kt @@ -2,34 +2,23 @@ package hep.dataforge.context import hep.dataforge.meta.Meta import hep.dataforge.meta.MetaBuilder -import hep.dataforge.provider.Type import kotlin.reflect.KClass -@Type(PluginFactory.TYPE) -public interface PluginFactory : Factory { - public val tag: PluginTag - public val type: KClass - - public companion object { - public const val TYPE: String = "pluginFactory" - } -} - /** * 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, plugins: Set) : ContextAware, Iterable { +public class PluginManager(override val context: Context) : ContextAware, Iterable { //TODO refactor to read-only container /** * A set of loaded plugins */ - private val plugins: HashSet = HashSet(plugins) + private val plugins: HashSet = HashSet() init { plugins.forEach { it.attach(context) } diff --git a/dataforge-context/src/commonTest/kotlin/hep/dataforge/context/ContextTest.kt b/dataforge-context/src/commonTest/kotlin/hep/dataforge/context/ContextTest.kt index 58647400..3d15e8b3 100644 --- a/dataforge-context/src/commonTest/kotlin/hep/dataforge/context/ContextTest.kt +++ b/dataforge-context/src/commonTest/kotlin/hep/dataforge/context/ContextTest.kt @@ -17,13 +17,13 @@ class ContextTest { else -> emptyMap() } } + } @Test fun testPluginManager() { - val context = Global.context("test"){ - plugin(DummyPlugin()) - } + val context = Global.context("test") + context.plugins.load(DummyPlugin()) //Global.plugins.load(DummyPlugin()) val members = context.gather("test") assertEquals(3, members.count()) diff --git a/dataforge-meta/api/dataforge-meta.api b/dataforge-meta/api/dataforge-meta.api index 06b46d01..3e85187f 100644 --- a/dataforge-meta/api/dataforge-meta.api +++ b/dataforge-meta/api/dataforge-meta.api @@ -299,18 +299,6 @@ public final class hep/dataforge/meta/MetaSerializer : kotlinx/serialization/KSe public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V } -public final class hep/dataforge/meta/MetaWithDefault : hep/dataforge/meta/MetaBase { - public fun (Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/ItemProvider;)V - public final fun getDefault ()Lhep/dataforge/meta/ItemProvider; - public fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem; - public fun getItems ()Ljava/util/Map; - public final fun getMeta ()Lhep/dataforge/meta/Meta; -} - -public final class hep/dataforge/meta/MetaWithDefaultKt { - public static final fun withDefault (Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/MetaWithDefault; -} - public final class hep/dataforge/meta/MutableItemDelegateKt { public static final fun boolean (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; public static final fun boolean (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty; diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ItemProvider.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ItemProvider.kt index 194a3398..7811e308 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ItemProvider.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ItemProvider.kt @@ -24,7 +24,7 @@ public operator fun ItemProvider?.get(name: Name): MetaItem? = this?.getItem(nam /** * Root item of this provider */ -public val ItemProvider.rootItem: MetaItem? get() = get(Name.EMPTY) +public val ItemProvider.rootItem: MetaItem? get() = get(Name.EMPTY) /** * The root node of this item provider if it is present @@ -39,8 +39,12 @@ public operator fun ItemProvider?.get(key: String): MetaItem? = this?.get(key.to /** * Create a provider that uses given provider for default values if those are not found in this provider */ -public fun ItemProvider.withDefault(default: ItemProvider): ItemProvider = ItemProvider { - this[it] ?: default[it] +public fun ItemProvider.withDefault(default: ItemProvider?): ItemProvider = if (default == null) { + this +} else { + ItemProvider { + this[it] ?: default[it] + } } /** @@ -71,7 +75,7 @@ public fun ItemProvider.getIndexed(name: String): Map = this@ */ public fun ItemProvider.getChild(childName: Name): ItemProvider = get(childName).node ?: ItemProvider.EMPTY -public fun ItemProvider.getChild(childName: String): ItemProvider = getChild(childName.toName()) +public fun ItemProvider.getChild(childName: String): ItemProvider = getChild(childName.toName()) ///** // * Get all items matching given name. diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaWithDefault.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaWithDefault.kt deleted file mode 100644 index 1858bd3c..00000000 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaWithDefault.kt +++ /dev/null @@ -1,18 +0,0 @@ -package hep.dataforge.meta - -import hep.dataforge.names.Name -import hep.dataforge.names.NameToken - -/** - * Meta object with default provider for items not present in the initial meta. - */ -public class MetaWithDefault(public val meta: Meta, public val default: ItemProvider) : MetaBase() { - override val items: Map - get() = meta.items - - override fun getItem(name: Name): MetaItem? { - return meta[name] ?: default[name] - } -} - -public fun Meta.withDefault(default: ItemProvider): MetaWithDefault = MetaWithDefault(this, default) \ No newline at end of file diff --git a/dataforge-workspace/src/jvmTest/kotlin/hep/dataforge/workspace/DataPropagationTest.kt b/dataforge-workspace/src/jvmTest/kotlin/hep/dataforge/workspace/DataPropagationTest.kt index 083d3f57..784a7441 100644 --- a/dataforge-workspace/src/jvmTest/kotlin/hep/dataforge/workspace/DataPropagationTest.kt +++ b/dataforge-workspace/src/jvmTest/kotlin/hep/dataforge/workspace/DataPropagationTest.kt @@ -56,8 +56,7 @@ class DataPropagationTestPlugin : WorkspacePlugin() { override val type: KClass = DataPropagationTestPlugin::class - override fun invoke(meta: Meta, context: Context): DataPropagationTestPlugin = - DataPropagationTestPlugin(meta) + override fun invoke(meta: Meta, context: Context): DataPropagationTestPlugin = DataPropagationTestPlugin() override val tag: PluginTag = PluginTag("Test") } @@ -66,7 +65,7 @@ class DataPropagationTestPlugin : WorkspacePlugin() { class DataPropagationTest { val testWorkspace = Workspace { context { - plugin(DataPropagationTestPlugin()) + plugin(DataPropagationTestPlugin) } data { repeat(100) { diff --git a/dataforge-workspace/src/jvmTest/kotlin/hep/dataforge/workspace/SimpleWorkspaceTest.kt b/dataforge-workspace/src/jvmTest/kotlin/hep/dataforge/workspace/SimpleWorkspaceTest.kt index e97f4be8..34bfd734 100644 --- a/dataforge-workspace/src/jvmTest/kotlin/hep/dataforge/workspace/SimpleWorkspaceTest.kt +++ b/dataforge-workspace/src/jvmTest/kotlin/hep/dataforge/workspace/SimpleWorkspaceTest.kt @@ -1,17 +1,23 @@ package hep.dataforge.workspace -import hep.dataforge.context.PluginTag -import hep.dataforge.context.logger +import hep.dataforge.context.* import hep.dataforge.data.* -import hep.dataforge.meta.boolean -import hep.dataforge.meta.builder -import hep.dataforge.meta.get -import hep.dataforge.meta.int +import hep.dataforge.meta.* import hep.dataforge.names.plus +import kotlin.reflect.KClass import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue +/** + * Make a fake-factory for a one single plugin. Useful for unique or test plugins + */ +public inline fun P.toFactory(): PluginFactory

= object : PluginFactory

{ + override fun invoke(meta: Meta, context: Context): P = this@toFactory + + override val tag: PluginTag = this@toFactory.tag + override val type: KClass = P::class +} class SimpleWorkspaceTest { val testPlugin = object : WorkspacePlugin() { @@ -23,11 +29,12 @@ class SimpleWorkspaceTest { } } } + val testPluginFactory = testPlugin.toFactory() val workspace = Workspace { context { - plugin(testPlugin) + plugin(testPluginFactory) } data {