onsdag 7 april 2010

Actors in java with akka, cont

I continue where my last post left us.
We now have a fully working chat, we can send messages and we will recieve messages that other users send.
The system is far from perfect. Lets try to improve it.

When i send a message, i have to wait until the server has sent it out to all the users before i can send another message, or look at the log. We could just wrap it in a Runnable and use a executor to make the call async. But that is pretty uggly code, and it can soon start to lead to problems.
Instead, lets use akka to introduce actors. if you want to know why and what actors are, there are alot of reading on the web. you can start with akka's homepage for ex: www.akkasource.org

first, we need to add the akka repository and dependency to our maven pom.

   <repositories>
        <repository>
            <id>akka.repository</id>
            <name>Akka Maven Repository</name>
            <url>http://scalablesolutions.se/akka/repository</url>
        </repository>
    </repositories>
and
        <dependency>
            <groupId>se.scalablesolutions.akka</groupId>
            <artifactId>akka-core_2.8.0.Beta1</artifactId>
            <version>0.8</version>
        </dependency>


now lets change some code, remember the testcase we had? with the Guice Injector, lets rewrite that.


public class IntegrationTest {

    ActiveObjectConfigurator conf = new ActiveObjectConfigurator();

    @Before
    public void setup() {
        MessageDispatcher dispatcher = Dispatchers.newExecutorBasedEventDrivenDispatcher("test");
        conf.addExternalGuiceModule(new AbstractModule() {

            @Override
            protected void configure() {
                bind(ChatSession.class);
            }
        }).configure(new RestartStrategy(new AllForOne(), 3, 5000, new Class[]{Exception.class}),
                new Component[]{
                    new Component(ChatServer.class, new LifeCycle(new Permanent()), 10000, dispatcher)}).inject().supervise();
    }

    @Test
    public void integrationTest() throws InterruptedException {
        final ChatSession userOne = conf.getExternalDependency(ChatSession.class);
        userOne.setUserName("userOne");
        userOne.login();
        final ChatSession userTwo = conf.getExternalDependency(ChatSession.class);
        final ChatSession userThree = conf.getExternalDependency(ChatSession.class);
        userTwo.setUserName("userTwo");
        userTwo.login();
        Thread.sleep(100); //to ensure login is done
        userOne.sendMessage("Hello");
        userTwo.sendMessage("Another Message 1");
        assertEquals(2, userOne.getLog().size());
        assertEquals(2, userTwo.getLog().size());
        assertEquals(userTwo.getLog(), userOne.getLog());

    }
}


As you can see, not much have changed.
We still have our guiceModule where we configure ChatSession.
But now we have a ActiveObjectConfigurator, we could call this an extension to guice. For now, ignore all the Strange things like RestartStrategy and LifeCycles we will look at them later.
lets look at the integrationTest method, the only difference here is that instead of creating a GuiceInjector, we use the ActiveObjectConfigurator, and with getExternalDependency, we can get an instance of ChatSession. But now, every method is fire and forget. ie, after we call the method we will return immediatly.

Now we have a much more scalable solution. next, it is time to store our messages in a database.

1 kommentar:

  1. You use MessageDispatcher here, but at the http://github.com/bobo/akka_sample_java/blob/a802d4ff2d9b2be428d9a4c84628e629390ab177/src/test/java/se/rty/akka/akka_sample_java/IntegrationTest.java you have both

    MessageDispatcher dispatcher = Dispatchers.newExecutorBasedEventDrivenDispatcher("test");

    and

    RemoteAddress address = new RemoteAddress("localhost", 11234);

    but use the address only...

    SvaraRadera