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\] `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

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 static final field Companion Lhep/dataforge/context/Context$Companion;
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 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 <init> (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 <init> (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 <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;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;

View File

@ -25,7 +25,6 @@ public open class Context(
final override val name: Name,
public val parent: Context?,
meta: Meta,
plugins: Set<Plugin> = 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

View File

@ -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<Plugin>()
private val factories = HashMap<PluginFactory<*>, 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<*>>(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)
}
}
}
}

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.MetaBuilder
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"
}
}
/**
* 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<Plugin>) : ContextAware, Iterable<Plugin> {
public class PluginManager(override val context: Context) : ContextAware, Iterable<Plugin> {
//TODO refactor to read-only container
/**
* A set of loaded plugins
*/
private val plugins: HashSet<Plugin> = HashSet(plugins)
private val plugins: HashSet<Plugin> = HashSet()
init {
plugins.forEach { it.attach(context) }

View File

@ -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<Name>("test")
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 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 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;

View File

@ -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<String?, MetaItem> = 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.

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 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) {

View File

@ -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 <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 {
val testPlugin = object : WorkspacePlugin() {
@ -23,11 +29,12 @@ class SimpleWorkspaceTest {
}
}
}
val testPluginFactory = testPlugin.toFactory()
val workspace = Workspace {
context {
plugin(testPlugin)
plugin(testPluginFactory)
}
data {