Refactor context factories

This commit is contained in:
Alexander Nozik 2020-12-28 21:05:27 +03:00
parent 027d5ed923
commit 030f3ed6fe
12 changed files with 56 additions and 76 deletions

View File

@ -17,6 +17,7 @@
- \[Major breaking change\] Schemes and configurables us `MutableItemProvider` instead of `Config` - \[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\] `MetaItem` renamed to `TypedMetaItem` and `MetaItem` is now an alias for `TypedMetaItem<*>`
- \[Major breaking change\] Moved `NodeItem` and `ValueItem` to a top level - \[Major breaking change\] Moved `NodeItem` and `ValueItem` to a top level
- Plugins are removed from Context constructor and added lazily in ContextBuilder
### Deprecated ### Deprecated

View File

@ -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 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 Companion Lhep/dataforge/context/Context$Companion;
public static final field PROPERTY_TARGET Ljava/lang/String; public static final field PROPERTY_TARGET Ljava/lang/String;
public fun <init> (Lhep/dataforge/names/Name;Lhep/dataforge/context/Context;Lhep/dataforge/meta/Meta;Ljava/util/Set;)V public fun <init> (Lhep/dataforge/names/Name;Lhep/dataforge/context/Context;Lhep/dataforge/meta/Meta;)V
public synthetic fun <init> (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 close ()V
public fun content (Ljava/lang/String;)Ljava/util/Map; public fun content (Ljava/lang/String;)Ljava/util/Map;
public final fun content (Ljava/lang/String;Z)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 <init> (Lhep/dataforge/context/Context;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public synthetic fun <init> (Lhep/dataforge/context/Context;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun build ()Lhep/dataforge/context/Context; public final fun build ()Lhep/dataforge/context/Context;
public final fun getName ()Ljava/lang/String; 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/PluginFactory;Lkotlin/jvm/functions/Function1;)V
public final fun plugin (Lhep/dataforge/context/PluginTag;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 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 final class hep/dataforge/context/PluginManager : hep/dataforge/context/ContextAware, java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker {
public fun <init> (Lhep/dataforge/context/Context;Ljava/util/Set;)V public fun <init> (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;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 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; 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;

View File

@ -25,7 +25,6 @@ public open class Context(
final override val name: Name, final override val name: Name,
public val parent: Context?, public val parent: Context?,
meta: Meta, meta: Meta,
plugins: Set<Plugin> = emptySet(),
) : Named, MetaRepr, Provider, CoroutineScope { ) : Named, MetaRepr, Provider, CoroutineScope {
/** /**
@ -40,7 +39,7 @@ public open class Context(
/** /**
* A [PluginManager] for current 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 override val defaultTarget: String get() = Plugin.TARGET

View File

@ -8,17 +8,13 @@ import hep.dataforge.names.toName
*/ */
@DFBuilder @DFBuilder
public class ContextBuilder(private val parent: Context = Global, public var name: String = "@anonymous") { public class ContextBuilder(private val parent: Context = Global, public var name: String = "@anonymous") {
private val plugins = HashSet<Plugin>() private val factories = HashMap<PluginFactory<*>, Meta>()
private var meta = MetaBuilder() private var meta = MetaBuilder()
public fun properties(action: MetaBuilder.() -> Unit) { public fun properties(action: MetaBuilder.() -> Unit) {
meta.action() meta.action()
} }
public fun plugin(plugin: Plugin) {
plugins.add(plugin)
}
@OptIn(DFExperimental::class) @OptIn(DFExperimental::class)
private fun findPluginFactory(tag: PluginTag): PluginFactory<*> = private fun findPluginFactory(tag: PluginTag): PluginFactory<*> =
parent.gatherInSequence<PluginFactory<*>>(PluginFactory.TYPE).values parent.gatherInSequence<PluginFactory<*>>(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 = {}) { public fun plugin(tag: PluginTag, metaBuilder: MetaBuilder.() -> Unit = {}) {
val factory = findPluginFactory(tag) val factory = findPluginFactory(tag)
val plugin = factory.invoke(Meta(metaBuilder), parent) factories[factory] = Meta(metaBuilder)
plugins.add(plugin)
} }
public fun plugin(builder: PluginFactory<*>, action: MetaBuilder.() -> Unit = {}) { public fun plugin(factory: PluginFactory<*>, metaBuilder: MetaBuilder.() -> Unit = {}) {
plugins.add(builder.invoke(Meta(action))) factories[factory] = Meta(metaBuilder)
} }
public fun plugin(name: String, group: String = "", version: String = "", action: MetaBuilder.() -> Unit = {}) { 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 { 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)
}
}
} }
} }

View File

@ -0,0 +1,14 @@
package hep.dataforge.context
import hep.dataforge.provider.Type
import kotlin.reflect.KClass
@Type(PluginFactory.TYPE)
public interface PluginFactory<T : Plugin> : Factory<T> {
public val tag: PluginTag
public val type: KClass<out T>
public companion object {
public const val TYPE: String = "pluginFactory"
}
}

View File

@ -2,34 +2,23 @@ package hep.dataforge.context
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder import hep.dataforge.meta.MetaBuilder
import hep.dataforge.provider.Type
import kotlin.reflect.KClass import kotlin.reflect.KClass
@Type(PluginFactory.TYPE)
public interface PluginFactory<T : Plugin> : Factory<T> {
public val tag: PluginTag
public val type: KClass<out T>
public companion object {
public const val TYPE: String = "pluginFactory"
}
}
/** /**
* The manager for plugin system. Should monitor plugin dependencies and locks. * The manager for plugin system. Should monitor plugin dependencies and locks.
* *
* @property context A context for this plugin manager * @property context A context for this plugin manager
* @author Alexander Nozik * @author Alexander Nozik
*/ */
public class PluginManager(override val context: Context, plugins: Set<Plugin>) : ContextAware, Iterable<Plugin> { public class PluginManager(override val context: Context) : ContextAware, Iterable<Plugin> {
//TODO refactor to read-only container //TODO refactor to read-only container
/** /**
* A set of loaded plugins * A set of loaded plugins
*/ */
private val plugins: HashSet<Plugin> = HashSet(plugins) private val plugins: HashSet<Plugin> = HashSet()
init { init {
plugins.forEach { it.attach(context) } plugins.forEach { it.attach(context) }

View File

@ -17,13 +17,13 @@ class ContextTest {
else -> emptyMap() else -> emptyMap()
} }
} }
} }
@Test @Test
fun testPluginManager() { fun testPluginManager() {
val context = Global.context("test"){ val context = Global.context("test")
plugin(DummyPlugin()) context.plugins.load(DummyPlugin())
}
//Global.plugins.load(DummyPlugin()) //Global.plugins.load(DummyPlugin())
val members = context.gather<Name>("test") val members = context.gather<Name>("test")
assertEquals(3, members.count()) assertEquals(3, members.count())

View File

@ -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 synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
} }
public final class hep/dataforge/meta/MetaWithDefault : hep/dataforge/meta/MetaBase {
public fun <init> (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 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/properties/ReadWriteProperty;
public static final fun boolean (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty; public static final fun boolean (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty;

View File

@ -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 * 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 { public fun ItemProvider.withDefault(default: ItemProvider?): ItemProvider = if (default == null) {
this
} else {
ItemProvider {
this[it] ?: default[it] this[it] ?: default[it]
}
} }
/** /**

View File

@ -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<NameToken, MetaItem>
get() = meta.items
override fun getItem(name: Name): MetaItem? {
return meta[name] ?: default[name]
}
}
public fun Meta.withDefault(default: ItemProvider): MetaWithDefault = MetaWithDefault(this, default)

View File

@ -56,8 +56,7 @@ class DataPropagationTestPlugin : WorkspacePlugin() {
override val type: KClass<out DataPropagationTestPlugin> = DataPropagationTestPlugin::class override val type: KClass<out DataPropagationTestPlugin> = DataPropagationTestPlugin::class
override fun invoke(meta: Meta, context: Context): DataPropagationTestPlugin = override fun invoke(meta: Meta, context: Context): DataPropagationTestPlugin = DataPropagationTestPlugin()
DataPropagationTestPlugin(meta)
override val tag: PluginTag = PluginTag("Test") override val tag: PluginTag = PluginTag("Test")
} }
@ -66,7 +65,7 @@ class DataPropagationTestPlugin : WorkspacePlugin() {
class DataPropagationTest { class DataPropagationTest {
val testWorkspace = Workspace { val testWorkspace = Workspace {
context { context {
plugin(DataPropagationTestPlugin()) plugin(DataPropagationTestPlugin)
} }
data { data {
repeat(100) { repeat(100) {

View File

@ -1,17 +1,23 @@
package hep.dataforge.workspace package hep.dataforge.workspace
import hep.dataforge.context.PluginTag import hep.dataforge.context.*
import hep.dataforge.context.logger
import hep.dataforge.data.* import hep.dataforge.data.*
import hep.dataforge.meta.boolean import hep.dataforge.meta.*
import hep.dataforge.meta.builder
import hep.dataforge.meta.get
import hep.dataforge.meta.int
import hep.dataforge.names.plus import hep.dataforge.names.plus
import kotlin.reflect.KClass
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
/**
* Make a fake-factory for a one single plugin. Useful for unique or test plugins
*/
public inline fun <reified P: Plugin> P.toFactory(): PluginFactory<P> = object : PluginFactory<P> {
override fun invoke(meta: Meta, context: Context): P = this@toFactory
override val tag: PluginTag = this@toFactory.tag
override val type: KClass<out P> = P::class
}
class SimpleWorkspaceTest { class SimpleWorkspaceTest {
val testPlugin = object : WorkspacePlugin() { val testPlugin = object : WorkspacePlugin() {
@ -23,11 +29,12 @@ class SimpleWorkspaceTest {
} }
} }
} }
val testPluginFactory = testPlugin.toFactory()
val workspace = Workspace { val workspace = Workspace {
context { context {
plugin(testPlugin) plugin(testPluginFactory)
} }
data { data {