From 7ec0493923f383dbf4904925993a02362bd9716d Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Tue, 18 Aug 2015 16:10:29 +0200 Subject: [PATCH] =per #18219 Find plugin constructor automatically --- akka-docs/rst/java/lambda-persistence.rst | 6 +++ akka-docs/rst/java/persistence.rst | 6 +++ .../persistence/PersistenceMultiDocSpec.scala | 6 +-- akka-docs/rst/scala/persistence.rst | 6 +++ .../src/main/resources/reference.conf | 14 +++---- .../scala/akka/persistence/Persistence.scala | 8 +++- .../akka/persistence/LoadPluginSpec.scala | 38 +++++++++++++++++++ 7 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 akka-persistence/src/test/scala/akka/persistence/LoadPluginSpec.scala diff --git a/akka-docs/rst/java/lambda-persistence.rst b/akka-docs/rst/java/lambda-persistence.rst index fec5eb3213..15b10b11d2 100644 --- a/akka-docs/rst/java/lambda-persistence.rst +++ b/akka-docs/rst/java/lambda-persistence.rst @@ -763,6 +763,9 @@ The journal plugin instance is an actor so the methods corresponding to requests are executed sequentially. It may delegate to asynchronous libraries, spawn futures, or delegate to other actors to achive parallelism. +The journal plugin class must have a constructor without parameters or constructor with one ``com.typesafe.config.Config`` +parameter. The plugin section of the actor system's config will be passed in the config constructor parameter. + Don't run journal tasks/futures on the system default dispatcher, since that might starve other tasks. Snapshot store plugin API @@ -783,6 +786,9 @@ The snapshot store instance is an actor so the methods corresponding to requests are executed sequentially. It may delegate to asynchronous libraries, spawn futures, or delegate to other actors to achive parallelism. +The snapshot store plugin class must have a constructor without parameters or constructor with one ``com.typesafe.config.Config`` +parameter. The plugin section of the actor system's config will be passed in the config constructor parameter. + Don't run snapshot store tasks/futures on the system default dispatcher, since that might starve other tasks. Pre-packaged plugins diff --git a/akka-docs/rst/java/persistence.rst b/akka-docs/rst/java/persistence.rst index 2cfe0ff49a..8bb7029c53 100644 --- a/akka-docs/rst/java/persistence.rst +++ b/akka-docs/rst/java/persistence.rst @@ -713,6 +713,9 @@ The journal plugin instance is an actor so the methods corresponding to requests are executed sequentially. It may delegate to asynchronous libraries, spawn futures, or delegate to other actors to achive parallelism. +The journal plugin class must have a constructor without parameters or constructor with one ``com.typesafe.config.Config`` +parameter. The plugin section of the actor system's config will be passed in the config constructor parameter. + Don't run journal tasks/futures on the system default dispatcher, since that might starve other tasks. Snapshot store plugin API @@ -733,6 +736,9 @@ The snapshot store instance is an actor so the methods corresponding to requests are executed sequentially. It may delegate to asynchronous libraries, spawn futures, or delegate to other actors to achive parallelism. +The snapshot store plugin class must have a constructor without parameters or constructor with one ``com.typesafe.config.Config`` +parameter. The plugin section of the actor system's config will be passed in the config constructor parameter. + Don't run snapshot store tasks/futures on the system default dispatcher, since that might starve other tasks. Plugin TCK diff --git a/akka-docs/rst/scala/code/docs/persistence/PersistenceMultiDocSpec.scala b/akka-docs/rst/scala/code/docs/persistence/PersistenceMultiDocSpec.scala index d319e87d5c..6487dcdc17 100644 --- a/akka-docs/rst/scala/code/docs/persistence/PersistenceMultiDocSpec.scala +++ b/akka-docs/rst/scala/code/docs/persistence/PersistenceMultiDocSpec.scala @@ -29,17 +29,13 @@ object PersistenceMultiDocSpec { class = "akka.persistence.chronicle.ChronicleSyncJournal" # Custom setting specific for the journal `ChronicleSyncJournal`. folder = ${user.dir}/store/journal - # Standard persistence extension property: plugin actor uses config injection. - inject-config = true - } + } # Configuration entry for the custom snapshot store plugin, see `snapshotPluginId`. akka.persistence.chronicle.snapshot-store { # Standard persistence extension property: provider FQCN. class = "akka.persistence.chronicle.ChronicleSnapshotStore" # Custom setting specific for the snapshot store `ChronicleSnapshotStore`. folder = ${user.dir}/store/snapshot - # Standard persistence extension property: plugin actor uses config injection. - inject-config = true } //#override-config """ diff --git a/akka-docs/rst/scala/persistence.rst b/akka-docs/rst/scala/persistence.rst index c09dbc600f..39e561118d 100644 --- a/akka-docs/rst/scala/persistence.rst +++ b/akka-docs/rst/scala/persistence.rst @@ -773,6 +773,9 @@ The journal plugin instance is an actor so the methods corresponding to requests are executed sequentially. It may delegate to asynchronous libraries, spawn futures, or delegate to other actors to achive parallelism. +The journal plugin class must have a constructor without parameters or constructor with one ``com.typesafe.config.Config`` +parameter. The plugin section of the actor system's config will be passed in the config constructor parameter. + Don't run journal tasks/futures on the system default dispatcher, since that might starve other tasks. Snapshot store plugin API @@ -793,6 +796,9 @@ The snapshot store instance is an actor so the methods corresponding to requests are executed sequentially. It may delegate to asynchronous libraries, spawn futures, or delegate to other actors to achive parallelism. +The snapshot store plugin class must have a constructor without parameters or constructor with one ``com.typesafe.config.Config`` +parameter. The plugin section of the actor system's config will be passed in the config constructor parameter. + Don't run snapshot store tasks/futures on the system default dispatcher, since that might starve other tasks. Plugin TCK diff --git a/akka-persistence/src/main/resources/reference.conf b/akka-persistence/src/main/resources/reference.conf index 750515793a..6c439ec826 100644 --- a/akka-persistence/src/main/resources/reference.conf +++ b/akka-persistence/src/main/resources/reference.conf @@ -6,13 +6,15 @@ # Make your edits in your application.conf in order to override these settings. # Note that both journal and snapshot store plugin configuration entries require few fields: -# `class` : Fully qualified class name providing journal-plugin-api or snapshot-store-plugin-api implementation. -# `inject-config` : Plugin actor has a constructor which expects plugin configuration entry. This boolean field is optional. +# `class` : Fully qualified class name providing journal-plugin-api or snapshot-store-plugin-api implementation, +# The class must have a constructor without parameters or constructor with +# one `com.typesafe.config.Config` parameter. # `plugin-dispatcher` : Absolute configuration path to the akka dispatcher configuration entry. This string field is optional. # Note that journal and snapshot store plugins included with the extension are suitable for testing purposes only. # You should change extension defaults or override `journalPluginId` and `snapshotPluginId` in the persistent actor or view. -# Directory of persistence journal and snapshot store plugins is available at the Akka Community Projects page http://akka.io/community/ +# Directory of persistence journal and snapshot store plugins is available at the Akka Community Projects page +# http://akka.io/community/ # Default persistence extension settings. akka.persistence { @@ -89,10 +91,6 @@ akka.persistence { # Dispatcher for message replay. replay-dispatcher = "akka.persistence.dispatchers.default-replay-dispatcher" - # Set this to true if plugin actor has a constructor which expects plugin - # configuration entry. - inject-config = false - # Maximum size of a persistent message batch written to the journal. max-message-batch-size = 200 @@ -130,8 +128,6 @@ akka.persistence { # Dispatcher for the plugin actor. plugin-dispatcher = "akka.persistence.dispatchers.default-plugin-dispatcher" - inject-config = false - circuit-breaker { max-failures = 5 call-timeout = 20s diff --git a/akka-persistence/src/main/scala/akka/persistence/Persistence.scala b/akka-persistence/src/main/scala/akka/persistence/Persistence.scala index 1c468dedcb..de476e26ae 100644 --- a/akka-persistence/src/main/scala/akka/persistence/Persistence.scala +++ b/akka-persistence/src/main/scala/akka/persistence/Persistence.scala @@ -14,6 +14,8 @@ import com.typesafe.config.Config import scala.annotation.tailrec import scala.concurrent.duration._ import java.util.Locale +import akka.util.Reflect +import scala.util.control.NonFatal /** * Persistence configuration. @@ -254,9 +256,11 @@ class Persistence(val system: ExtendedActorSystem) extends Extension { val pluginClassName = pluginConfig.getString("class") log.debug(s"Create plugin: $pluginActorName $pluginClassName") val pluginClass = system.dynamicAccess.getClassFor[Any](pluginClassName).get - val pluginInjectConfig = pluginConfig.getBoolean("inject-config") val pluginDispatcherId = pluginConfig.getString("plugin-dispatcher") - val pluginActorArgs = if (pluginInjectConfig) List(pluginConfig) else Nil + val pluginActorArgs = try { + Reflect.findConstructor(pluginClass, List(pluginConfig)) // will throw if not found + List(pluginConfig) + } catch { case NonFatal(_) ⇒ Nil } // otherwise use empty constructor val pluginActorProps = Props(Deploy(dispatcher = pluginDispatcherId), pluginClass, pluginActorArgs) system.systemActorOf(pluginActorProps, pluginActorName) } diff --git a/akka-persistence/src/test/scala/akka/persistence/LoadPluginSpec.scala b/akka-persistence/src/test/scala/akka/persistence/LoadPluginSpec.scala new file mode 100644 index 0000000000..34e6e2fc58 --- /dev/null +++ b/akka-persistence/src/test/scala/akka/persistence/LoadPluginSpec.scala @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2015 Typesafe Inc. + */ + +package akka.persistence + +import akka.persistence.journal.inmem.InmemJournal +import com.typesafe.config.Config +import akka.testkit.ImplicitSender +import akka.actor.Actor + +object LoadJournalSpec { + + case object GetConfig + + class JournalWithConfig(val config: Config) extends InmemJournal { + override def receivePluginInternal: Actor.Receive = { + case GetConfig ⇒ sender() ! config + } + } +} + +class LoadJournalSpec extends PersistenceSpec(PersistenceSpec.config("inmem", "LoadJournalSpec", extraConfig = Some( + """ + akka.persistence.journal.inmem.class = "akka.persistence.LoadJournalSpec$JournalWithConfig" + akka.persistence.journal.inmem.extra-property = 17 + """))) with ImplicitSender { + import LoadJournalSpec._ + + "A journal with config parameter" must { + "be created with plugin config" in { + val journalRef = Persistence(system).journalFor("akka.persistence.journal.inmem") + journalRef ! GetConfig + expectMsgType[Config].getInt("extra-property") should be(17) + } + } +} +