Add preemptive initialization for plugins

This commit is contained in:
Alexander Nozik 2020-11-10 20:18:54 +03:00
parent d5992c721d
commit 3ab3f2766c
5 changed files with 28 additions and 63 deletions

View File

@ -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 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;)V public fun <init> (Lhep/dataforge/names/Name;Lhep/dataforge/context/Context;Lhep/dataforge/meta/Meta;Ljava/util/Set;)V
public final fun activate (Ljava/lang/Object;)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;
public final fun deactivate (Ljava/lang/Object;)V
public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext; public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext;
public fun getDefaultChainTarget ()Ljava/lang/String; public fun getDefaultChainTarget ()Ljava/lang/String;
public fun getDefaultTarget ()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 getName ()Lhep/dataforge/names/Name;
public final fun getParent ()Lhep/dataforge/context/Context; public final fun getParent ()Lhep/dataforge/context/Context;
public final fun getPlugins ()Lhep/dataforge/context/PluginManager; public final fun getPlugins ()Lhep/dataforge/context/PluginManager;
public final fun isActive ()Z
public fun toMeta ()Lhep/dataforge/meta/Meta; 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 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;)V public fun <init> (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;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

@ -28,6 +28,7 @@ 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 {
/** /**
@ -47,32 +48,7 @@ public open class Context(
/** /**
* A [PluginManager] for current context * A [PluginManager] for current context
*/ */
public val plugins: PluginManager = PluginManager(this) public val plugins: PluginManager by lazy { PluginManager(this, plugins)}
@Deprecated("To be removed in favor of immutable plugins")
private val activators = HashSet<Any>()
/**
* 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)
}
override val defaultTarget: String get() = Plugin.TARGET override val defaultTarget: String get() = Plugin.TARGET
@ -104,8 +80,6 @@ public open class Context(
* Detach all plugins and terminate context * Detach all plugins and terminate context
*/ */
public open fun close() { public open fun close() {
@Suppress("DEPRECATION")
if (isActive) error("Can't close active context")
//detach all plugins //detach all plugins
plugins.forEach { it.detach() } plugins.forEach { it.detach() }
} }

View File

@ -8,7 +8,7 @@ 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 = ArrayList<Plugin>() private val plugins = HashSet<Plugin>()
private var meta = MetaBuilder() private var meta = MetaBuilder()
public fun properties(action: MetaBuilder.() -> Unit) { public fun properties(action: MetaBuilder.() -> Unit) {
@ -20,9 +20,12 @@ public class ContextBuilder(private val parent: Context = Global, public var nam
} }
@OptIn(DFExperimental::class) @OptIn(DFExperimental::class)
public fun plugin(tag: PluginTag, metaBuilder: MetaBuilder.() -> Unit = {}) { private fun findPluginFactory(tag: PluginTag): PluginFactory<*> =
val factory = parent.gatherInSequence<PluginFactory<*>>(PluginFactory.TYPE).values parent.gatherInSequence<PluginFactory<*>>(PluginFactory.TYPE).values
.find { it.tag.matches(tag) } ?: error("Can't resolve plugin factory for $tag") .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) val plugin = factory.invoke(Meta(metaBuilder), parent)
plugins.add(plugin) plugins.add(plugin)
} }
@ -36,10 +39,6 @@ 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()).apply { return Context(name.toName(), parent, meta.seal(), plugins)
this@ContextBuilder.plugins.forEach {
plugins.load(it)
}
}
} }
} }

View File

@ -16,21 +16,24 @@ public interface PluginFactory<T : Plugin> : Factory<T> {
} }
} }
/** /**
* 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) : ContextAware, Iterable<Plugin> { public class PluginManager(override val context: Context, plugins: Set<Plugin>) : 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>() private val plugins: HashSet<Plugin> = HashSet(plugins)
init {
plugins.forEach { it.attach(context) }
}
/** /**
* A [PluginManager] of parent context if it is present * 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? = public fun find(inherit: Boolean = true, predicate: (Plugin) -> Boolean): Plugin? =
list(inherit).find(predicate) list(inherit).find(predicate)
/** /**
* Find a loaded plugin via its tag * 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? = public operator fun get(tag: PluginTag, inherit: Boolean = true): Plugin? =
find(inherit) { tag.matches(it.tag) } 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 * 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. * plugin matching the class condition.
@ -96,10 +97,8 @@ public class PluginManager(override val context: Context) : ContextAware, Iterab
* @return * @return
*/ */
public fun <T : Plugin> load(plugin: T): T { public fun <T : Plugin> load(plugin: T): T {
if (context.isActive) error("Can't load plugin into active context")
if (get(plugin::class, plugin.tag, recursive = false) != null) { 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 { } else {
for (tag in plugin.dependsOn()) { for (tag in plugin.dependsOn()) {
fetch(tag, true) fetch(tag, true)
@ -125,8 +124,6 @@ public class PluginManager(override val context: Context) : ContextAware, Iterab
* Remove a plugin from [PluginManager] * Remove a plugin from [PluginManager]
*/ */
public fun remove(plugin: Plugin) { public fun remove(plugin: Plugin) {
if (context.isActive) error("Can't remove plugin from active context")
if (plugins.contains(plugin)) { if (plugins.contains(plugin)) {
logger.info { "Removing plugin ${plugin.name} from ${context.name}" } logger.info { "Removing plugin ${plugin.name} from ${context.name}" }
plugin.detach() 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 * Get an existing plugin with given meta or load new one using provided factory
*
*/ */
public fun <T : Plugin> fetch(factory: PluginFactory<T>, recursive: Boolean = true, meta: Meta = Meta.EMPTY): T { public fun <T : Plugin> fetch(factory: PluginFactory<T>, recursive: Boolean = true, meta: Meta = Meta.EMPTY): T {
val loaded = get(factory.type, factory.tag, recursive) val loaded = get(factory.type, factory.tag, recursive)

View File

@ -45,25 +45,23 @@ public interface Workspace : ContextAware, Provider {
* Invoke a task in the workspace utilizing caching if possible * Invoke a task in the workspace utilizing caching if possible
*/ */
public fun <R : Any> run(task: Task<R>, config: Meta): DataNode<R> { public fun <R : Any> run(task: Task<R>, config: Meta): DataNode<R> {
context.activate(this)
try {
val model = task.build(this, config) val model = task.build(this, config)
task.validate(model) task.validate(model)
return task.run(this, model) return task.run(this, model)
} finally {
context.deactivate(this)
}
} }
public companion object { public companion object {
public const val TYPE: String = "workspace" 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() SimpleWorkspaceBuilder(parent).apply(block).build()
} }
} }
public fun Workspace.run(task: Task<*>, target: String): DataNode<Any> { public fun Workspace.run(task: Task<*>, target: String): DataNode<Any> {
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) return run(task, meta)
} }