Switch branches/tags
Nothing to show
Find file History
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
..
Failed to load latest commit information.
src
Makefile
README
pom.xml
testng.xml

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.