How to define a wrapper function/class addActorToSystem() for
trait Stage extends Actor
class Stage1(i:Int) extends Stage
class Stage2(i:Int) extends Stage
and
implicit val system = ActorSystem("mySystem")
instead of the call to
system.actorOf(Props(new Stage1(123)), "myStage1")
The following does not work
You cannot create an instance of [Stage2] explicitly using the constructor (new)
def addActorToSystem(act: Stage, i: Int)(name: String)(implicit sys: ActorSystem) = {
sys.actorOf(Props(act(i)), name)
}
Maybe something like this would help you:
def addActorToSystem[T <: Stage](act: Class[T], i: Int)(name: String)(implicit sys: ActorSystem) = {
sys.actorOf(Props(act, i), name)
}
And usage like follows:
val s1 = addActorToSystem(classOf[Stage1], 1)("s1")
val s2 = addActorToSystem(classOf[Stage2], 2)("s2")
Creating actor without ActorContext defined (by using constructor) is not allowed.
The only one reason why this works in Props is the fact that constructor invocation is handled as by-name parameter thus its evaluation is deffered
Related
I am learning Scala and Akka and I came across an example that confused me. The following code sample was in 1 file.
class RestApi(system: ActorSystem, timeout: Timeout) extends RestRoutes {
implicit val requestTimeout = timeout
implicit def executionContext = system.dispatcher
def createBoxOffice = system.actorOf(BoxOffice.props, BoxOffice.name)
}
trait BoxOfficeApi {
import BoxOffice._
def createBoxOffice(): ActorRef
implicit def executionContext: ExecutionContext
implicit def requestTimeout: Timeout
lazy val boxOffice = createBoxOffice()
// Uninteresting methods here
}
The part that confuses me is the createBoxOffice() call in the BoxOfficeAPI trait. It clearly states that the BoxOfficeAPI has a function which will return an ActorRef. However the implementation for that function is located in the RestApi class which doesn't have any reference to the trait.
How is it possible that the trait can access this method? What is the scope of a trait?
How is it possible that the trait can access this method?
I think you're missing the fact that the trait itself has an abstract method called createBoxOffice:
def createBoxOffice(): ActorRef
Which is why it has such a method in scope. It has nothing to do with the declaration of RestApi. Whoever mixes in this trait will have to implement that said method. That means, for example, that if the RestApi class decides to mix in BoxOfficeApi, it already has an implementation available which it will use. For example:
class Baz extends Foo {
override def quuux(): Unit = println("quuux")
}
trait Foo {
def quuux(): Unit
}
Is it possible to create an akka actor that has implicits in the constructor?
Having:
class Actor(parameter: Long)(implicit service:Service)
and
class Service
can I use the context to create the actor like this?
implicit val service:Service = new Service()
val someLong = 3
context.actorOf(FromConfig.props(Props(classOf[Actor], someLong)), "actor")
As a mention the service cannot be passed to the constructor because multiple different actor classes can be received, which use different implicits from the scope.
Define your Props in Companion object of Actor and is good for injecting Dependencies.
class SomeActor(parameter: Long)(implicit service:Service) extends Actor {
def receive = {
case message => // Do your stuff
}
}
object SomeActor {
def props(parameter: Long)(implicit service:Service) = Props(new SomeActor(parameter))
}
implicit val service:Service = new Service()
val someLong = 3
val ref = context.actorOf(SomeActor.props(someLong)), "actor")
and you can read more about Dependency Injection here :
http://doc.akka.io/docs/akka/snapshot/scala/actors.html#Dependency_Injection
http://letitcrash.com/post/55958814293/akka-dependency-injection
I'd like to reduce the boilerplate needed to bind these akka actors.
At current, my code looks like this:
bind(classOf[ActorRef]).
annotatedWith(Names.named("mines")).
toProvider(new TypeLiteral[ActorProvider[MyActor]]() {}).
asEagerSingleton()
I'd like it too look like:
bindActor[MyActor].withName("mines")
I've tried to subclass AbstractModule to squeeze this concept in to no avail.
Pertinent code:
class ActorProvider[T <: Actor] #Inject() ( val key:Key[T], val injector:Injector, val system: ActorSystem ) extends Provider[ActorRef] {
def get = {
system.actorOf(Props(injector.getInstance(key)))
}
}
Check out https://github.com/codingwell/scala-guice/. Here is a sample based on it. It allows for
bindActor[MyActor].withName("mines")
Keep in mind you are binding a non-generic ActorRef and not Actor itself. This will create a binding for #Named("foo") ActorRef. You should never work with Actor directly.
You cannot get Key in the provider. Provider doesn't take any contextual injections like you tried with the Key or e.g. Injection Point. What you can do is create a different instance of the provider for each actor binding and inject it with ActorSystem afterwards. Alternatively you could change the API to include the actor system instance aswell.
trait AkkaModule extends AbstractModule {
// should be:
// this: AbstractModule =>
// see http://lampsvn.epfl.ch/trac/scala/ticket/3564
import ScalaModule._
private def binderAccess = super.binder // shouldn't need super
def bindActor[T <: Actor](implicit m: Manifest[T]) = new ActorBindingBuilder {
//Hack, no easy way to exclude the bind method that gets added to classes inheriting ScalaModule
//So we experamentally figured out how many calls up is the source, so we use that
//Commit 52c2e92f8f6131e4a9ea473f58be3e32cd172ce6 has better class exclusion
val mybinder = binderAccess.withSource((new Throwable).getStackTrace()(3))
val self = (mybinder bind classOf[ActorRef]).asInstanceOf[AnnotatedBindingBuilder[ActorRef]]
}
}
object AkkaModule {
class ActorProvider(val name: String) extends Provider[ActorRef] {
#Inject var system: ActorSystem = _
def get = {
system.actorFor(system.name + "/user/" + name)
}
}
trait ActorBindingBuilder {
val mybinder: Binder
val self: AnnotatedBindingBuilder[ActorRef]
def withName(name: String) = {
val provider = new ActorProvider(name)
self.annotatedWith(Names.named(name)).toProvider(provider)
mybinder.requestInjection(provider)
}
}
}
Something like this that leverages scala's type Manifest might work
http://www.scala-lang.org/api/current/scala/reflect/Manifest.html
where Foo is analogous to ActorRef and Bla is analogous to MyActor:
scala> import com.google.inject
import com.google.inject
scala> val binder:inject.Binder = null
binder: com.google.inject.Binder = null
scala> class Foo {}
defined class Foo
scala> class Bla extends Foo {}
defined class Bla
scala> def bind[T <: Foo:Manifest] = binder.bind( classOf[Foo] ).toProvider( new
inject.TypeLiteral[inject.Provider[T]](){} ).asEagerSingleton
bind: [T <: Foo](implicit evidence$1: Manifest[T])Unit
Maybe combine that with implicit conversion to convert a Binder to a MyBinder:
http://daily-scala.blogspot.com/2009/08/implicit-methods.html
class MyBinder {
def bindActor[T <: ActorRef:Manifest]( nameToBind:String ):Unit = ...
}
object MyBinder {
implicit def binderToMyBinder( ...
}
Good luck!
Trying to find a valid and flexible way to store a sequence of class types in Scala that I can later use to spin up new instances of that type:
class Event(
val name: String,
val channels: Seq[String],
val processors: Seq[T] // a sequence of processor classes
)
Each processor in the sequence above is an Akka Actor class. I plan on creating a new Actor every time data is received by mapping out the processors like so:
event.processors.foreach { processorType =>
val processor = newProcessor(processorType) // does all the Akka creation stuff
processor ! Data
}
Update: apparently the above is rather correct, so how do we enforce that Seq[T] is processor-types only? So sticking in classes like class Calculator extends Processor
My guess is that there are some gotchas with Scala that I missed, so thanks for your help.
Seq[T] would only be valid if there is either a type T or a type parameter.
scala> class Event(val seq:Seq[T])
<console>:7: error: not found: type T
class Event(val seq:Seq[T])
^
To have a list of classes it has to be of a Seq[Class[_]].
Let's suppose the processors you mention are of type Processor. A smaller illustrative example:
scala> trait Processor; class P1 extends Processor; class P2 extends Processor
scala> case class Event(val seq:Seq[Class[_ <: Processor]])
defined class Event
scala> Event(List(classOf[P1],classOf[P2]))
res4: Event = Event(List(class P1, class P2))
scala> res4.seq map { _.newInstance }
res6: Seq[Processor] = List(P1#43655bee, P2#337688d3)
This is what Props is made for. The advantage of using Props is that you could pass whatever parameters you want to your Processor constructors at runtime, instead of being restricted to using no-arg constructors.
One thing to note about Props is that it take a by-name creator argument, so when you see Props(new TestActor) the TestActor is not actually created at that moment. It is created when you pass the Props to actorOf().
To restrict the Actors to be a subtype of Processor you could create a subtype of Props.
For example:
trait Processor extends Actor
class MyProps(creat: () ⇒ Processor) extends Props(creat)
object MyProps {
def apply(creator: ⇒ Processor): MyProps = new MyProps(() => creator)
}
Your Event class would have a Seq[MyProps]. Here's a sample test:
case class Event(
name: String,
channels: Seq[String],
processors: Seq[MyProps]
)
class TestActor(bar: String) extends Processor {
def receive = {
case msg # _ => println(bar + " " + msg)
}
}
object SeqProps extends App {
override def main(args: Array[String]) {
val system = ActorSystem()
val event = new Event("test", Seq("chan1", "chan2", "chan3"),
Seq(MyProps(new TestActor("baz")),
MyProps(new TestActor("barz"))))
event.processors.foreach { proc =>
system.actorOf(proc) ! "go!"
}
system.shutdown()
}
}
If you tried to pass a non-Processor to MyProps() it would fail at compile time.
scala> class NotProcessor extends Actor {
| def receive = emptyBehavior
| }
defined class NotProcessor
scala> MyProps(new NotProcessor)
<console>:15: error: type mismatch;
found : NotProcessor
required: Processor
MyProps(new NotProcessor)
^
I am trying to define a case class with some params that have a default value, but the default value requires an implicit parameter. I've tried something like this:
case class ChannelLatches(started: TestLatch, stopped: TestLatch)(implicit system: ActorSystem) {
def this()(implicit system: ActorSystem) = this(new TestLatch(), new TestLatch())(system)
}
and this:
case class ChannelLatches(started: TestLatch, stopped: TestLatch)(implicit system: ActorSystem) {
def this()(implicit system: ActorSystem) = this(new TestLatch(), new TestLatch())(system)
}
but in both cases, the compiler does not recognize my new constructor. Any pointers?
The issue is not in the case class or its constructor. When you get compilation error like
scala> val channelLatches = new ChannelLatches
<console>:11: error: could not find implicit value for parameter system: ActorSystem
val channelLatches = new ChannelLatches
^
it means that you don't have an implicit variable of type ActorSystem available as a single identifier in the scope.
Both your code examples (they are exactly the same code, right?) and #Eastsun's example are perfectly legal code:
scala> class ActorSystem
defined class ActorSystem
scala> class TestLatch
defined class TestLatch
scala> case class ChannelLatches(started: TestLatch = new TestLatch, stopped: TestLatch = new TestLatch)(implicit system: ActorSystem)
defined class ChannelLatches
scala> implicit val actor = new ActorSystem
actor: ActorSystem = ActorSystem#586f403e
scala> val channelLatches = new ChannelLatches
channelLatches: ChannelLatches = ChannelLatches(TestLatch#521a74af,TestLatch#46e2b745)
Note the implicit val actor which makes it possible for the compiler to supply the missing parameter implicitly.
See A Tour of Scala: Implicit Parameters for introduction about implicit parameters.
--- Edit 2012-03-05: Added alternative example where ChannelLatches is inner class of Something
If you want ChannelLatches to be an inner class of something, you really don't need to pass the ActorSystem instance to the inner class instances as inner classes can access values from outer objects. A Tour of Scala: Inner Classes
scala> class ActorSystem
defined class ActorSystem
scala> class TestLatch
defined class TestLatch
scala> class Something(implicit val as: ActorSystem) {
| case class ChannelLatches(started: TestLatch, stopped: TestLatch) {
| def this() = this(new TestLatch(), new TestLatch())
|
| def actorSystem = as
| }
| }
defined class Something
scala> implicit val as = new ActorSystem
as: ActorSystem = ActorSystem#5481be8a
scala> val s = new Something
s: Something = Something#7139acf
scala> val cl = new s.ChannelLatches
cl: s.ChannelLatches = ChannelLatches(TestLatch#38764254,TestLatch#5bfcb5c1)
scala> cl.actorSystem == as
res0: Boolean = true