Documentation adjustment for Context

This commit is contained in:
Alexander Nozik 2018-12-12 14:13:12 +03:00
parent 139a78beca
commit abf222434f
3 changed files with 33 additions and 9 deletions

View File

@ -10,6 +10,18 @@ import mu.KLogger
import mu.KotlinLogging import mu.KotlinLogging
import kotlin.reflect.KClass import kotlin.reflect.KClass
/**
* The local environment for anything being done in DataForge framework. Contexts are organized into tree structure with [Global] at the top.
* Context has [properties] - equivalent for system environment values, but grouped into a tree and inherited from parent context.
*
* The main function of the Context is to provide [PluginManager] which stores the loaded plugins and works as a dependency injection point.
* The normal behaviour of the [PluginManager] is to search for a plugin in parent context if it is not found in a current one. It is possible to have
* different plugins with the same interface in different contexts in the hierarchy. The usual behaviour is to use nearest one, but it could
* be overridden by plugin implementation.
*
* Since plugins could contain mutable state, context has two states: active and inactive. No changes are allowed to active context.
* @author Alexander Nozik
*/
interface Context : Named, MetaRepr, Provider { interface Context : Named, MetaRepr, Provider {
val parent: Context? val parent: Context?
@ -24,6 +36,9 @@ interface Context : Named, MetaRepr, Provider {
*/ */
val logger: KLogger val logger: KLogger
/**
* A [PluginManager] for current context
*/
val plugins: PluginManager val plugins: PluginManager
/** /**

View File

@ -19,6 +19,9 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
*/ */
private val plugins = HashSet<Plugin>() private val plugins = HashSet<Plugin>()
/**
* A [PluginManager] of parent context if it is present
*/
private val parent: PluginManager? = context.parent?.plugins private val parent: PluginManager? = context.parent?.plugins
@ -31,7 +34,9 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
} }
/** /**
* Get for existing plugin * Get existing plugin or return null if not present. Only first matching plugin is returned.
* @param recursive search for parent [PluginManager] plugins
* @param predicate condition for the plugin
*/ */
fun get(recursive: Boolean = true, predicate: (Plugin) -> Boolean): Plugin? = sequence(recursive).find(predicate) fun get(recursive: Boolean = true, predicate: (Plugin) -> Boolean): Plugin? = sequence(recursive).find(predicate)
@ -87,6 +92,9 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
} }
} }
/**
* Remove a plugin from [PluginManager]
*/
fun remove(plugin: Plugin) { fun remove(plugin: Plugin) {
if (context.isActive) error("Can't remove plugin from active context") if (context.isActive) error("Can't remove plugin from active context")
@ -98,7 +106,7 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
} }
/** /**
* Get plugin instance via plugin reolver and load it. * Get plugin instance via plugin resolver and load it.
* *
* @param tag * @param tag
* @return * @return
@ -114,6 +122,7 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
/** /**
* Load plugin by its class and meta. Ignore if plugin with this meta is already loaded. * Load plugin by its class and meta. Ignore if plugin with this meta is already loaded.
* Throw an exception if there exists plugin with the same type, but different meta
*/ */
fun <T : Plugin> load(type: KClass<T>, meta: Meta = EmptyMeta): T { fun <T : Plugin> load(type: KClass<T>, meta: Meta = EmptyMeta): T {
val loaded = get(type, false) val loaded = get(type, false)
@ -142,4 +151,11 @@ class PluginManager(override val context: Context) : ContextAware, Iterable<Plug
override fun iterator(): Iterator<Plugin> = plugins.iterator() override fun iterator(): Iterator<Plugin> = plugins.iterator()
/**
* Get a plugin if it exists or load it with given meta if it is not.
*/
inline fun <reified T : Plugin> getOrLoad(noinline metaBuilder: MetaBuilder.() -> Unit = {}): T {
return get(true) ?: load(metaBuilder)
}
} }

View File

@ -26,13 +26,6 @@ import kotlin.collections.HashSet
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.full.cast import kotlin.reflect.full.cast
/**
* The local environment for anything being done in DataForge framework. Contexts are organized into tree structure with [Global] at the top.
* Each context has a set of named [Value] properties which are taken from parent context in case they are not found in local context.
* Context implements [ValueProvider] interface and therefore could be uses as a value source for substitutions etc.
* Context contains [PluginManager] which could be used any number of configurable named plugins.
* @author Alexander Nozik
*/
open class JVMContext( open class JVMContext(
final override val name: String, final override val name: String,
final override val parent: JVMContext? = Global, final override val parent: JVMContext? = Global,