Add preemptive initialization for plugins
This commit is contained in:
parent
d5992c721d
commit
3ab3f2766c
@ -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;
|
||||||
|
@ -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() }
|
||||||
}
|
}
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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)
|
||||||
|
@ -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)
|
val model = task.build(this, config)
|
||||||
try {
|
task.validate(model)
|
||||||
val model = task.build(this, config)
|
return task.run(this, model)
|
||||||
task.validate(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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,5 +75,5 @@ public fun Workspace.run(task: String, meta: Meta): DataNode<Any> =
|
|||||||
public fun Workspace.run(task: String, block: MetaBuilder.() -> Unit = {}): DataNode<Any> =
|
public fun Workspace.run(task: String, block: MetaBuilder.() -> Unit = {}): DataNode<Any> =
|
||||||
run(task, Meta(block))
|
run(task, Meta(block))
|
||||||
|
|
||||||
public fun <T: Any> Workspace.run(task: Task<T>, metaBuilder: MetaBuilder.() -> Unit = {}): DataNode<T> =
|
public fun <T : Any> Workspace.run(task: Task<T>, metaBuilder: MetaBuilder.() -> Unit = {}): DataNode<T> =
|
||||||
run(task, Meta(metaBuilder))
|
run(task, Meta(metaBuilder))
|
Loading…
Reference in New Issue
Block a user