Skip to content

Instantly share code, notes, and snippets.

@SalomonBrys
Created December 16, 2020 18:18
Show Gist options
  • Save SalomonBrys/121cd7ebdd94a771d878e86d4729545d to your computer and use it in GitHub Desktop.
Save SalomonBrys/121cd7ebdd94a771d878e86d4729545d to your computer and use it in GitHub Desktop.
Example that shows how to create a scope registry according to a server environment.
import org.kodein.di.*
import org.kodein.di.bindings.Scope
import org.kodein.di.bindings.ScopeRegistry
import org.kodein.di.bindings.StandardScopeRegistry
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicReference
enum class Environment(val baseUrl: String) {
DEBUG("http://localhost"),
PROD("https://api.awesome-service.com")
}
data class CurrentEnvironment(var env: Environment)
class API(val baseUrl: String) {
override fun toString(): String = "Manager ${System.identityHashCode(this)} with baseUrl $baseUrl"
}
/** This simple scope keeps one registry per environment and never clears them */
object EnvironmentScope : Scope<Environment> {
private val registries = ConcurrentHashMap<Environment, ScopeRegistry>()
override fun getRegistry(context: Environment): ScopeRegistry = registries.getOrPut(context) { StandardScopeRegistry() }
}
/** This more complex scope only keeps one registry according to the latest provided environment */
object OneEnvironmentScope : Scope<Environment> {
data class Current(val env: Environment, val reg: ScopeRegistry)
private var currentReference: AtomicReference<Current?> = AtomicReference(null)
override fun getRegistry(context: Environment): ScopeRegistry {
var current = currentReference.get()
// If this is the first time accessing the scope, we create the registry according to the environment.
if (current == null) {
current = Current(context, StandardScopeRegistry())
if (!currentReference.compareAndSet(null, current)) return getRegistry(context)
}
// If a registry already exist and its environment is correct, we return it.
if (current.env == context) return current.reg
// Since the environment is incorrect, we create a new registry and clear the old one.
val previous = current
current = Current(context, StandardScopeRegistry())
if (!currentReference.compareAndSet(previous, current)) return getRegistry(context)
previous.reg.clear()
return current.reg
}
}
fun main() {
val currentEnv = CurrentEnvironment(Environment.PROD)
val di = DI {
// Choose one:
//bind() from scoped(EnvironmentScope).singleton { API(context.baseUrl) }
bind() from scoped(OneEnvironmentScope).singleton { API(context.baseUrl) }
// This is needed to provide Kodein-DI the mean to find the current env.
registerContextFinder<Environment> { currentEnv.env }
}
println(di.direct.instance<API>())
println(di.direct.instance<API>())
println()
currentEnv.env = Environment.DEBUG
println(di.direct.instance<API>())
println(di.direct.instance<API>())
println()
currentEnv.env = Environment.PROD
println(di.direct.instance<API>())
println(di.direct.instance<API>())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment