Creating ExtensionId, AbstractExtensionId, ExtensionIdProvider and Extension
This commit is contained in:
parent
bf20f3fa44
commit
603a8ed034
13 changed files with 85 additions and 60 deletions
|
|
@ -13,15 +13,22 @@ import static org.junit.Assert.*;
|
|||
|
||||
public class JavaExtension {
|
||||
|
||||
static class Provider implements ExtensionProvider {
|
||||
public Extension lookup() { return defaultInstance; }
|
||||
static class Provider implements ExtensionIdProvider {
|
||||
public ExtensionId lookup() { return defaultInstance; }
|
||||
}
|
||||
|
||||
public final static TestExtension defaultInstance = new TestExtension();
|
||||
public final static TestExtensionId defaultInstance = new TestExtensionId();
|
||||
|
||||
static class TestExtension extends AbstractExtension<ActorSystemImpl> {
|
||||
public ActorSystemImpl createExtension(ActorSystemImpl i) {
|
||||
return i;
|
||||
static class TestExtensionId extends AbstractExtensionId<TestExtension> {
|
||||
public TestExtension createExtension(ActorSystemImpl i) {
|
||||
return new TestExtension(i);
|
||||
}
|
||||
}
|
||||
|
||||
static class TestExtension implements Extension {
|
||||
public final ActorSystemImpl system;
|
||||
public TestExtension(ActorSystemImpl i) {
|
||||
system = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -32,8 +39,8 @@ public class JavaExtension {
|
|||
|
||||
@Test
|
||||
public void mustBeAccessible() {
|
||||
assertSame(system.extension(defaultInstance), system);
|
||||
assertSame(defaultInstance.apply(system), system);
|
||||
assertSame(system.extension(defaultInstance).system, system);
|
||||
assertSame(defaultInstance.apply(system).system, system);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,10 +10,12 @@ import com.typesafe.config.ConfigFactory
|
|||
class JavaExtensionSpec extends JavaExtension with JUnitSuite
|
||||
|
||||
object ActorSystemSpec {
|
||||
object TestExtension extends Extension[ActorSystem] with ExtensionProvider {
|
||||
object TestExtension extends ExtensionId[TestExtension] with ExtensionIdProvider {
|
||||
def lookup = this
|
||||
def createExtension(s: ActorSystemImpl) = s
|
||||
def createExtension(s: ActorSystemImpl) = new TestExtension(s)
|
||||
}
|
||||
|
||||
class TestExtension(val system: ActorSystemImpl) extends Extension
|
||||
}
|
||||
|
||||
class ActorSystemSpec extends AkkaSpec("""akka.extensions = ["akka.actor.ActorSystemSpec$TestExtension$"]""") {
|
||||
|
|
@ -22,8 +24,8 @@ class ActorSystemSpec extends AkkaSpec("""akka.extensions = ["akka.actor.ActorSy
|
|||
"An ActorSystem" must {
|
||||
|
||||
"support extensions" in {
|
||||
TestExtension(system) must be === system
|
||||
system.extension(TestExtension) must be === system
|
||||
TestExtension(system).system must be === system
|
||||
system.extension(TestExtension).system must be === system
|
||||
system.hasExtension(TestExtension) must be(true)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ abstract class ActorSystem extends ActorRefFactory with TypedActorFactory {
|
|||
* This method has putIfAbsent-semantics, this method can potentially block, waiting for the initialization
|
||||
* of the payload, if is in the process of registration from another Thread of execution
|
||||
*/
|
||||
def registerExtension[T <: AnyRef](ext: Extension[T]): T
|
||||
def registerExtension[T <: Extension](ext: ExtensionId[T]): T
|
||||
|
||||
/**
|
||||
* Returns the payload that is associated with the provided extension
|
||||
|
|
@ -264,13 +264,13 @@ abstract class ActorSystem extends ActorRefFactory with TypedActorFactory {
|
|||
* This method can potentially block, waiting for the initialization
|
||||
* of the payload, if is in the process of registration from another Thread of execution
|
||||
*/
|
||||
def extension[T <: AnyRef](ext: Extension[T]): T
|
||||
def extension[T <: Extension](ext: ExtensionId[T]): T
|
||||
|
||||
/**
|
||||
* Returns whether the specified extension is already registered, this method can potentially block, waiting for the initialization
|
||||
* of the payload, if is in the process of registration from another Thread of execution
|
||||
*/
|
||||
def hasExtension(ext: Extension[_ <: AnyRef]): Boolean
|
||||
def hasExtension(ext: ExtensionId[_ <: Extension]): Boolean
|
||||
}
|
||||
|
||||
class ActorSystemImpl(val name: String, val applicationConfig: Config) extends ActorSystem {
|
||||
|
|
@ -367,28 +367,30 @@ class ActorSystemImpl(val name: String, val applicationConfig: Config) extends A
|
|||
terminationFuture onComplete (_ ⇒ dispatcher.shutdown())
|
||||
}
|
||||
|
||||
private val extensions = new ConcurrentIdentityHashMap[Extension[_], AnyRef]
|
||||
private val extensions = new ConcurrentIdentityHashMap[ExtensionId[_], AnyRef]
|
||||
|
||||
/**
|
||||
* Returns any extension registered to the specified Extension or returns null if not registered
|
||||
*/
|
||||
@tailrec
|
||||
private def findExtension[T <: AnyRef](ext: Extension[T]): T = extensions.get(ext) match {
|
||||
private def findExtension[T <: Extension](ext: ExtensionId[T]): T = extensions.get(ext) match {
|
||||
case c: CountDownLatch ⇒ c.await(); findExtension(ext) //Registration in process, await completion and retry
|
||||
case other ⇒ other.asInstanceOf[T] //could be a T or null, in which case we return the null as T
|
||||
}
|
||||
|
||||
@tailrec
|
||||
final def registerExtension[T <: AnyRef](ext: Extension[T]): T = {
|
||||
final def registerExtension[T <: Extension](ext: ExtensionId[T]): T = {
|
||||
findExtension(ext) match {
|
||||
case null ⇒ //Doesn't already exist, commence registration
|
||||
val inProcessOfRegistration = new CountDownLatch(1)
|
||||
extensions.putIfAbsent(ext, inProcessOfRegistration) match { // Signal that registration is in process
|
||||
case null ⇒ try { // Signal was successfully sent
|
||||
val instance = ext.createExtension(this) // Create and initialize the extension
|
||||
if (instance == null) throw new IllegalStateException("Extension instance created as null for Extension: " + ext)
|
||||
ext.createExtension(this) match { // Create and initialize the extension
|
||||
case null ⇒ throw new IllegalStateException("Extension instance created as null for Extension: " + ext)
|
||||
case instance ⇒
|
||||
extensions.replace(ext, inProcessOfRegistration, instance) //Replace our in process signal with the initialized extension
|
||||
instance //Profit!
|
||||
}
|
||||
} catch {
|
||||
case t ⇒
|
||||
extensions.remove(ext, inProcessOfRegistration) //In case shit hits the fan, remove the inProcess signal
|
||||
|
|
@ -402,20 +404,21 @@ class ActorSystemImpl(val name: String, val applicationConfig: Config) extends A
|
|||
}
|
||||
}
|
||||
|
||||
def extension[T <: AnyRef](ext: Extension[T]): T = findExtension(ext) match {
|
||||
def extension[T <: Extension](ext: ExtensionId[T]): T = findExtension(ext) match {
|
||||
case null ⇒ throw new IllegalArgumentException("Trying to get non-registered extension " + ext)
|
||||
case some ⇒ some.asInstanceOf[T]
|
||||
}
|
||||
|
||||
def hasExtension(ext: Extension[_ <: AnyRef]): Boolean = findExtension(ext) != null
|
||||
def hasExtension(ext: ExtensionId[_ <: Extension]): Boolean = findExtension(ext) != null
|
||||
|
||||
private def loadExtensions() {
|
||||
import scala.collection.JavaConversions._
|
||||
settings.config.getStringList("akka.extensions") foreach { fqcn ⇒
|
||||
import ReflectiveAccess._
|
||||
getObjectFor[ExtensionProvider](fqcn).fold(_ ⇒ createInstance[ExtensionProvider](fqcn, noParams, noArgs), Right(_)) match {
|
||||
case Right(p: ExtensionProvider) ⇒ registerExtension(p.lookup())
|
||||
case Right(other) ⇒ log.error("'{}' is not an ExtensionProvider, skipping...", fqcn)
|
||||
getObjectFor[AnyRef](fqcn).fold(_ ⇒ createInstance[AnyRef](fqcn, noParams, noArgs), Right(_)) match {
|
||||
case Right(p: ExtensionIdProvider) ⇒ registerExtension(p.lookup());
|
||||
case Right(p: ExtensionId[_]) ⇒ registerExtension(p);
|
||||
case Right(other) ⇒ log.error("'{}' is not an ExtensionIdProvider or ExtensionId, skipping...", fqcn)
|
||||
case Left(problem) ⇒ log.error(problem, "While trying to load extension '{}', skipping...", fqcn)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,21 +17,35 @@ package akka.actor
|
|||
* to the ActorSystem implementation.
|
||||
*
|
||||
*/
|
||||
trait Extension[T <: AnyRef] {
|
||||
|
||||
/**
|
||||
* Market interface to signify an Akka Extension
|
||||
*/
|
||||
trait Extension
|
||||
|
||||
/**
|
||||
* Identifies an Extension
|
||||
* Lookup of Extensions is done by object identity, so the Id must be the same wherever it's used,
|
||||
* otherwise you'll get the same extension loaded multiple times.
|
||||
*/
|
||||
trait ExtensionId[T <: Extension] {
|
||||
def apply(system: ActorSystem): T = system.registerExtension(this)
|
||||
def createExtension(system: ActorSystemImpl): T
|
||||
}
|
||||
|
||||
/**
|
||||
* Java API for Extension
|
||||
* Java API for ExtensionId
|
||||
*/
|
||||
abstract class AbstractExtension[T <: AnyRef] extends Extension[T]
|
||||
abstract class AbstractExtensionId[T <: Extension] extends ExtensionId[T]
|
||||
|
||||
/**
|
||||
* To be able to load an Extension from the configuration,
|
||||
* a class that implements ExtensionProvider must be specified.
|
||||
* To be able to load an ExtensionId from the configuration,
|
||||
* a class that implements ExtensionIdProvider must be specified.
|
||||
* The lookup method should return the canonical reference to the extension.
|
||||
*/
|
||||
trait ExtensionProvider {
|
||||
def lookup(): Extension[_ <: AnyRef]
|
||||
trait ExtensionIdProvider {
|
||||
/**
|
||||
* Returns the canonical ExtensionId for this Extension
|
||||
*/
|
||||
def lookup(): ExtensionId[_ <: Extension]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ package akka.serialization
|
|||
|
||||
import akka.AkkaException
|
||||
import akka.util.ReflectiveAccess
|
||||
import akka.actor.{ ActorSystem, ActorSystemImpl }
|
||||
import scala.util.DynamicVariable
|
||||
import com.typesafe.config.{ ConfigRoot, ConfigParseOptions, ConfigFactory, Config }
|
||||
import com.typesafe.config.Config._
|
||||
import akka.config.ConfigurationException
|
||||
import akka.actor.{ Extension, ActorSystem, ActorSystemImpl }
|
||||
|
||||
case class NoSerializerFoundException(m: String) extends AkkaException(m)
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ object Serialization {
|
|||
* Serialization module. Contains methods for serialization and deserialization as well as
|
||||
* locating a Serializer for a particular class as defined in the mapping in the 'akka.conf' file.
|
||||
*/
|
||||
class Serialization(val system: ActorSystemImpl) {
|
||||
class Serialization(val system: ActorSystemImpl) extends Extension {
|
||||
import Serialization._
|
||||
|
||||
val settings = new Settings(system.applicationConfig)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@
|
|||
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
package akka.serialization
|
||||
import akka.actor.{ ExtensionProvider, Extension, ActorSystemImpl }
|
||||
|
||||
object SerializationExtension extends Extension[Serialization] with ExtensionProvider {
|
||||
import akka.actor.{ ExtensionId, ExtensionIdProvider, ActorSystemImpl }
|
||||
|
||||
object SerializationExtension extends ExtensionId[Serialization] with ExtensionIdProvider {
|
||||
override def lookup = SerializationExtension
|
||||
override def createExtension(system: ActorSystemImpl): Serialization = new Serialization(system)
|
||||
}
|
||||
|
|
@ -9,14 +9,14 @@ import com.typesafe.config.ConfigParseOptions
|
|||
import com.typesafe.config.ConfigRoot
|
||||
import akka.util.Duration
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import akka.actor.{ ExtensionProvider, ActorSystem, Extension, ActorSystemImpl }
|
||||
import akka.actor._
|
||||
|
||||
object BeanstalkBasedMailboxExtension extends Extension[BeanstalkMailboxSettings] with ExtensionProvider {
|
||||
object BeanstalkBasedMailboxExtension extends ExtensionId[BeanstalkMailboxSettings] with ExtensionIdProvider {
|
||||
def lookup() = this
|
||||
def createExtension(system: ActorSystemImpl) = new BeanstalkMailboxSettings(system.applicationConfig)
|
||||
}
|
||||
|
||||
class BeanstalkMailboxSettings(cfg: Config) {
|
||||
class BeanstalkMailboxSettings(cfg: Config) extends Extension {
|
||||
private def referenceConfig: Config =
|
||||
ConfigFactory.parseResource(classOf[ActorSystem], "/akka-beanstalk-mailbox-reference.conf",
|
||||
ConfigParseOptions.defaults.setAllowMissing(false))
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ import com.typesafe.config.ConfigParseOptions
|
|||
import com.typesafe.config.ConfigRoot
|
||||
import akka.util.Duration
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import akka.actor.{ ExtensionProvider, ActorSystem, Extension, ActorSystemImpl }
|
||||
import akka.actor._
|
||||
|
||||
object FileBasedMailboxExtension extends Extension[FileBasedMailboxSettings] with ExtensionProvider {
|
||||
object FileBasedMailboxExtension extends ExtensionId[FileBasedMailboxSettings] with ExtensionIdProvider {
|
||||
def lookup() = this
|
||||
def createExtension(system: ActorSystemImpl) = new FileBasedMailboxSettings(system.applicationConfig)
|
||||
}
|
||||
|
||||
class FileBasedMailboxSettings(cfg: Config) {
|
||||
class FileBasedMailboxSettings(cfg: Config) extends Extension {
|
||||
private def referenceConfig: Config =
|
||||
ConfigFactory.parseResource(classOf[ActorSystem], "/akka-file-mailbox-reference.conf",
|
||||
ConfigParseOptions.defaults.setAllowMissing(false))
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ import akka.util.Duration
|
|||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import akka.actor._
|
||||
|
||||
object MongoBasedMailboxExtension extends Extension[MongoBasedMailboxSettings] with ExtensionProvider {
|
||||
object MongoBasedMailboxExtension extends ExtensionId[MongoBasedMailboxSettings] with ExtensionIdProvider {
|
||||
def lookup() = this
|
||||
def createExtension(system: ActorSystemImpl) = new MongoBasedMailboxSettings(system.applicationConfig)
|
||||
}
|
||||
|
||||
class MongoBasedMailboxSettings(cfg: Config) {
|
||||
class MongoBasedMailboxSettings(cfg: Config) extends Extension {
|
||||
private def referenceConfig: Config =
|
||||
ConfigFactory.parseResource(classOf[ActorSystem], "/akka-mongo-mailbox-reference.conf",
|
||||
ConfigParseOptions.defaults.setAllowMissing(false))
|
||||
|
|
|
|||
|
|
@ -7,14 +7,14 @@ import com.typesafe.config.Config
|
|||
import com.typesafe.config.ConfigFactory
|
||||
import com.typesafe.config.ConfigParseOptions
|
||||
import com.typesafe.config.ConfigRoot
|
||||
import akka.actor.{ ExtensionProvider, ActorSystem, Extension, ActorSystemImpl }
|
||||
import akka.actor._
|
||||
|
||||
object RedisBasedMailboxExtension extends Extension[RedisBasedMailboxSettings] with ExtensionProvider {
|
||||
object RedisBasedMailboxExtension extends ExtensionId[RedisBasedMailboxSettings] with ExtensionIdProvider {
|
||||
def lookup() = this
|
||||
def createExtension(system: ActorSystemImpl) = new RedisBasedMailboxSettings(system.applicationConfig)
|
||||
}
|
||||
|
||||
class RedisBasedMailboxSettings(cfg: Config) {
|
||||
class RedisBasedMailboxSettings(cfg: Config) extends Extension {
|
||||
private def referenceConfig: Config =
|
||||
ConfigFactory.parseResource(classOf[ActorSystem], "/akka-redis-mailbox-reference.conf",
|
||||
ConfigParseOptions.defaults.setAllowMissing(false))
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ import com.typesafe.config.ConfigParseOptions
|
|||
import com.typesafe.config.ConfigRoot
|
||||
import akka.util.Duration
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import akka.actor.{ ExtensionProvider, ActorSystem, Extension, ActorSystemImpl }
|
||||
import akka.actor._
|
||||
|
||||
object ZooKeeperBasedMailboxExtension extends Extension[ZooKeeperBasedMailboxSettings] with ExtensionProvider {
|
||||
object ZooKeeperBasedMailboxExtension extends ExtensionId[ZooKeeperBasedMailboxSettings] with ExtensionIdProvider {
|
||||
def lookup() = this
|
||||
def createExtension(system: ActorSystemImpl) = new ZooKeeperBasedMailboxSettings(system.applicationConfig)
|
||||
}
|
||||
class ZooKeeperBasedMailboxSettings(cfg: Config) {
|
||||
class ZooKeeperBasedMailboxSettings(cfg: Config) extends Extension {
|
||||
private def referenceConfig: Config =
|
||||
ConfigFactory.parseResource(classOf[ActorSystem], "/akka-zookeeper-mailbox-reference.conf",
|
||||
ConfigParseOptions.defaults.setAllowMissing(false))
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@ import akka.config.ConfigurationException
|
|||
import com.eaio.uuid.UUID
|
||||
import akka.actor._
|
||||
|
||||
object RemoteExtension extends Extension[RemoteExtensionSettings] with ExtensionProvider {
|
||||
object RemoteExtension extends ExtensionId[RemoteExtensionSettings] with ExtensionIdProvider {
|
||||
def lookup() = this
|
||||
def createExtension(system: ActorSystemImpl) = new RemoteExtensionSettings(system.applicationConfig)
|
||||
}
|
||||
|
||||
class RemoteExtensionSettings(cfg: Config) {
|
||||
class RemoteExtensionSettings(cfg: Config) extends Extension {
|
||||
private def referenceConfig: Config =
|
||||
ConfigFactory.parseResource(classOf[ActorSystem], "/akka-remote-reference.conf",
|
||||
ConfigParseOptions.defaults.setAllowMissing(false))
|
||||
|
|
|
|||
|
|
@ -3,21 +3,19 @@
|
|||
*/
|
||||
package akka.testkit
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.actor.Extension
|
||||
import akka.actor.ActorSystemImpl
|
||||
import com.typesafe.config.Config
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import com.typesafe.config.ConfigParseOptions
|
||||
import com.typesafe.config.ConfigRoot
|
||||
import akka.util.Duration
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import akka.actor.{ ExtensionId, ActorSystem, Extension, ActorSystemImpl }
|
||||
|
||||
object TestKitExtension extends Extension[TestKitSettings] {
|
||||
object TestKitExtension extends ExtensionId[TestKitSettings] {
|
||||
def createExtension(system: ActorSystemImpl): TestKitSettings = new TestKitSettings(system.applicationConfig)
|
||||
}
|
||||
|
||||
class TestKitSettings(cfg: Config) {
|
||||
class TestKitSettings(cfg: Config) extends Extension {
|
||||
private def referenceConfig: Config =
|
||||
ConfigFactory.parseResource(classOf[ActorSystem], "/akka-testkit-reference.conf",
|
||||
ConfigParseOptions.defaults.setAllowMissing(false))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue