pekko/akka-persistence/src/main/scala/akka/persistence/PersistencePlugin.scala

104 lines
3.6 KiB
Scala
Raw Normal View History

/*
* Copyright (C) 2018-2019 Lightbend Inc. <https://www.lightbend.com>
*/
package akka.persistence
import java.util.concurrent.atomic.AtomicReference
import akka.actor.{ ExtendedActorSystem, Extension, ExtensionId }
import akka.annotation.InternalApi
import akka.event.Logging
import akka.persistence.PersistencePlugin.PluginHolder
import com.typesafe.config.Config
import scala.annotation.tailrec
import scala.reflect.ClassTag
import scala.util.Failure
/**
* INTERNAL API
*/
@InternalApi
private[akka] object PersistencePlugin {
2019-03-13 10:56:20 +01:00
final private[persistence] case class PluginHolder[ScalaDsl, JavaDsl](
scaladslPlugin: ScalaDsl,
javadslPlugin: JavaDsl)
2019-03-11 10:38:24 +01:00
extends Extension
}
/**
* INTERNAL API
*/
@InternalApi
private[akka] trait PluginProvider[T, ScalaDsl, JavaDsl] {
def scalaDsl(t: T): ScalaDsl
def javaDsl(t: T): JavaDsl
}
/**
* INTERNAL API
*/
@InternalApi
2019-03-11 10:38:24 +01:00
private[akka] abstract class PersistencePlugin[ScalaDsl, JavaDsl, T: ClassTag](system: ExtendedActorSystem)(
implicit ev: PluginProvider[T, ScalaDsl, JavaDsl]) {
private val plugins = new AtomicReference[Map[String, ExtensionId[PluginHolder[ScalaDsl, JavaDsl]]]](Map.empty)
private val log = Logging(system, getClass)
@tailrec
final protected def pluginFor(pluginId: String, readJournalPluginConfig: Config): PluginHolder[ScalaDsl, JavaDsl] = {
val configPath = pluginId
val extensionIdMap = plugins.get
extensionIdMap.get(configPath) match {
case Some(extensionId) =>
extensionId(system)
case None =>
val extensionId = new ExtensionId[PluginHolder[ScalaDsl, JavaDsl]] {
override def createExtension(system: ExtendedActorSystem): PluginHolder[ScalaDsl, JavaDsl] = {
val provider = createPlugin(configPath, readJournalPluginConfig)
2019-03-11 10:38:24 +01:00
PluginHolder(ev.scalaDsl(provider), ev.javaDsl(provider))
}
}
plugins.compareAndSet(extensionIdMap, extensionIdMap.updated(configPath, extensionId))
pluginFor(pluginId, readJournalPluginConfig)
}
}
private def createPlugin(configPath: String, readJournalPluginConfig: Config): T = {
val mergedConfig = readJournalPluginConfig.withFallback(system.settings.config)
2019-03-13 10:56:20 +01:00
require(
!isEmpty(configPath) && mergedConfig.hasPath(configPath),
s"'reference.conf' is missing persistence plugin config path: '$configPath'")
val pluginConfig = mergedConfig.getConfig(configPath)
val pluginClassName = pluginConfig.getString("class")
log.debug(s"Create plugin: $configPath $pluginClassName")
val pluginClass = system.dynamicAccess.getClassFor[AnyRef](pluginClassName).get
def instantiate(args: collection.immutable.Seq[(Class[_], AnyRef)]) =
system.dynamicAccess.createInstanceFor[T](pluginClass, args)
2019-03-11 10:38:24 +01:00
instantiate(
(classOf[ExtendedActorSystem], system) :: (classOf[Config], pluginConfig) ::
(classOf[String], configPath) :: Nil)
.recoverWith {
case _: NoSuchMethodException =>
2019-03-11 10:38:24 +01:00
instantiate((classOf[ExtendedActorSystem], system) :: (classOf[Config], pluginConfig) :: Nil)
}
.recoverWith { case _: NoSuchMethodException => instantiate((classOf[ExtendedActorSystem], system) :: Nil) }
.recoverWith { case _: NoSuchMethodException => instantiate(Nil) }
.recoverWith {
2019-03-11 10:38:24 +01:00
case ex: Exception =>
Failure.apply(
2019-03-13 10:56:20 +01:00
new IllegalArgumentException(
"Unable to create read journal plugin instance for path " +
s"[$configPath], class [$pluginClassName]!",
ex))
2019-03-11 10:38:24 +01:00
}
.get
}
/** Check for default or missing identity. */
private def isEmpty(text: String): Boolean = text == null || text.length == 0
}