This repository is private.
All pages are served over SSL and all pushing and pulling is done over SSH.
No one may fork, clone, or view it unless they are added as a member.
Every repository with this icon (
) is private.
Every repository with this icon (
This repository is public.
Anyone may fork, clone, or view it.
Every repository with this icon (
) is public.
Every repository with this icon (
commit 8eeddfea06d01de0d04157056db165733adcd796
tree ff0a2735098429a9a9d5aafe7ceeb3525f940db3
parent c4bfc676a398475c1cf2dc1c04ec45d2127b6878
tree ff0a2735098429a9a9d5aafe7ceeb3525f940db3
parent c4bfc676a398475c1cf2dc1c04ec45d2127b6878
scala-otp / component
component/README
This package implements asynchronous components, also known as Active Objects. Each component is a GenericServer that is
managed by a Supervisor, either in isolation or as part of a supervisor hierarchy/tree. The components creation is based
on dynamic proxies and the component has to be build up by an interface (trait) and a regular Scala class as
implementation. Each component is instantiated through a factory.
Here is a simple example of a component that is using default Supervisor management (which among other things mean that
it is not part of a hierarchy). We start with the component interface and implementation.
trait Foo {
def foo(msg: String): String
@oneway def bar(msg: String)
}
class FooImpl extends Foo {
def foo(msg: String): String = { println("foo: " + msg); msg }
def bar(msg: String) = println("bar: " + msg)
}
Now let's instantiate this component. The integer 100 specifies the time interval an (asynchronous) invocation should
have before timing out.
val foo = ActiveObject.newInstance[Foo](classOf[Foo], new FooImpl, 1000)
Now we can use this component as any regular instance of Foo. With the difference that:
* All invocations are asynchronous
* The default scheme is that all invocations are based on a Future waiting for the return value
* If a method is marked by the @scala.actors.annotation.oneway annotation then it return immediately
* The component is a fault-tolerant GenericServer managed by a Supervisor
foo.foo("foo ")
foo.bar("bar ") // returns immediately since annotated with @oneway
Now, if I would like to have more control over the Supervisor configuration and/or want to compose different components
into supervisor hierarchies, then I can use another factory method along with a method called 'start' that allows you to
pass in a Supervisor configuration.
Here is a full example:
trait Foo {
def foo(msg: String): String
@oneway def bar(msg: String)
}
class FooImpl extends Foo {
val bar: Bar = new BarImpl
def foo(msg: String): String = { println("foo: " + msg); msg }
def bar(msg: String) = bar.bar(msg)
}
trait Bar {
def bar(msg: String)
}
class BarImpl extends Bar {
def bar(msg: String) = println("bar: " + msg)
}
First create a proxy (GenericServer).
val fooProxy = new ActiveObjectProxy(new FooImpl, 1000)
val barProxy = new ActiveObjectProxy(new BarImpl, 1000)
Then configure the GenericServer(s) (this method takes a list of GenericServer configurations) by passing the proxy's
server. This configuration is passed into the 'supervise' method which also starts up the Supervisor which starts up all
GenericServer's according to their configurations before returning the Supervisor instance (which can be used for later
management).
val supervisor =
ActiveObject.supervise(
RestartStrategy(AllForOne, 3, 100),
Component(
fooProxy,
LifeCycle(Permanent, 100)) ::
Component(
barProxy,
LifeCycle(Permanent, 100))
:: Nil)
Create and use the components as usual.
val foo = ActiveObject.newInstance[Foo](classOf[Foo], fooProxy)
val bar = ActiveObject.newInstance[Bar](classOf[Bar], barProxy)
foo.foo("foo ")
bar.bar("bar ")
That pretty much sums it up. Try it out and send suggestions, improvements, patches etc. to jonas AT jonasboner DOT com.








