My favorites | Sign in
Logo
                
Search
for
Updated Jul 27, 2009 by sergio.bossa
Labels: Featured
GettingStarted  

Getting Started Tutorial

This tutorial will walk you through some basic Actorom concepts and capabilities by showing you how to write a simple ping-pong sample program based on the Actor Concurrency Model.

We want two actors exchanging a fixed number of ping-pong messages.
We want a ping actor, upon receiving of a start message, to send ping messages to a pong actor which will respond back with pong messages, until a pre-configured number of ping-pong messages is exchanged. The ping actor is linked to the pong actor, meaning that the former will send a special exit message to the latter prior to exiting itself; so, when the max number of messages is exchanged, the ping actor will end the communication by exiting, causing the pong actor to exit too.

Let's start!

Messages

We can start our sample application by coding the messages that make up our communication.

The StartMessage, which will start the ping-pong exchange by communicating the "pong actor" address and configuring the max number of exchanges.

private static class StartMessage {

    private Address pongActorAddress;
    private int maxMessages;

    public StartMessage(Address pongActorAddress, int maxMessages) {
        this.pongActorAddress = pongActorAddress;
        this.maxMessages = maxMessages;
    }

    public Address getPongActorAddress() {
        return pongActorAddress;
    }

    public int getMaxMessages() {
        return maxMessages;
    }

    @Override
    public String toString() {
        return START_MESSAGE;
    }
}

The PingMessage and PongMessage:

public class PingMessage implements Serializable {

    @Override
    public String toString() {
        return PING_MESSAGE;
    }
}
public class PongMessage implements Serializable {

    @Override
    public String toString() {
        return PONG_MESSAGE;
    }
}

Messages are implemented as plain old Java objects, with no specific class to extend or interface to implement (except the java.io.Serializable interface needed only if you plan to use remote actors as we will see next): you have full control over your business logic, and the way you want to implement it.

Let's move on and see how to write our actors.

Actors and handlers

In Actorom you can focus on the way actors will react on specific messages by writing so called actor handlers, plain old Java objects with properly annotated methods for reacting on specific lifecycle events.

Going into details, here is the PingActor, with its PongActor companion:

public class PingActorHandler {

    @TopologyInstance private Topology topology;
    private Address pongActorAddress;
    private int maxMessages;
    private int actualMessages = 0;

    @OnMessage(type = StartMessage.class)
    public void onStart(StartMessage message) {
        pongActorAddress = message.getPongActorAddress();
        maxMessages = message.getMaxMessages();
        Actor pongActor = topology.getActor(pongActorAddress);
        if (pongActor != null) {
            pongActor.send(new PingMessage());
            actualMessages++;
        }
    }

    @OnMessage(type = PongMessage.class)
    public void onPong(PongMessage message) {
        Actor pongActor = topology.getActor(pongActorAddress);
        if (pongActor != null) {
            if (actualMessages < maxMessages) {
                pongActor.send(new PingMessage());
            } else {
                throw new KillActorException();
            }
        }
    }
}
public class PongActorHandler {

    @TopologyInstance private Topology topology;
    private Address pingActorAddress;

    public PongActorHandler(Address pingActorAddress) {
        this.pingActorAddress = pingActorAddress;
    }

    @OnMessage(type = PingMessage.class)
    public void onPing(PingMessage message) {
        Actor pingActor = topology.getActor(pingActorAddress);
        if (pingActor != null) {
            pingActor.send(new PongMessage());
        }
    }
}

A few things to notice:

All available annotations are into the com.googlecode.actorom.annotation package.

Again there's no particular class to extend, nor any bytecode instrumentation phase: everything is plain old Java, which integrates seamlessly with your standard development and build process.

Let's see now how to actually create and work with our actors, by using local and client/server topologies.

Topologies and threading policies

Topologies are the main access point for actors, used for spawning and retrieving them.

Actors are spawned by providing a unique string identifier and their handler object: the topology will give you back an address object to use for retrieving the actual actor instance.

We have two different type of topologies:

When you create a topology, you can also specify the threading policy to use for spawned actors, which defines the actual thread management policy for actually handling actor messages.
We have two different policies:

You can switch between the two by passing the proper implementation, obtained through the ThreadingPolicies static factory, to the topology constructor.

Here is how to spawn our previously described actors through a local topology:

// Create the local topology, with "local" as symbolic host name 
// used to uniquely identifying the topology, and lightweight (green) threads:
Topology topology = new LocalTopology("local", ThreadingPolicies.newGreenThreadingPolicy());

// Spawn actors:
Address pingAddress = topology.spawnActor(PING_ACTOR, new PingActorHandler());
Address pongAddress = topology.spawnActor(PONG_ACTOR, new PongActorHandler(pingAddress));

// Retrieve actor instances:
Actor pingActor = topology.getActor(pingAddress);
Actor pongActor = topology.getActor(pongAddress);

And here is how to use client/server topologies instead:

// Create the server topology, with host and port to listen to:
ServerTopology serverTopology = new ServerTopology("127.0.0.1", 1234, ThreadingPolicies.newGreenThreadingPolicy());
// Create the client topology, with host and port of the server topology to connect to, plus a number of parameters to control the communication link:
ClientTopology clientTopology = new ClientTopology("127.0.0.1", 2345, 1, TimeUnit.SECONDS, 1, TimeUnit.SECONDS, 3);

// Spawn actors on server topology:
Address pingAddress = serverTopology.spawnActor(PING_ACTOR, new PingActorHandler());
Address pongAddress = serverTopology.spawnActor(PONG_ACTOR, new PongActorHandler(pingAddress));

// Retrieve actors from client topology:
Actor pingActor = clientTopology.getActor(pingAddress);
Actor pongActor = clientTopology.getActor(pongAddress);

As you can see, messages and actor handlers implementations remained unchanged.

Working with actors

Once you have your actor instances spawned and ready to be used, you can start to implement your message-passing logic.

First, we need to link PingActor to PongActor, so that when the former will exit, the latter will exit too:

pingActor.link(pongActor);

Then, we just need to send the StartMessage to PingActor:

pingActor.send(new StartMessage(pongAddress, MAX_MESSAGES));

Now, we're ready to run!

Run the sample!

Let's finally run the sample, using a local topology (with client/server topologies it would be almost the same, just copy/paste the snippets above):

public class PingPong {

    public static final String PING_ACTOR = "PING_ACTOR";
    public static final String PONG_ACTOR = "PONG_ACTOR";
    public static final int MAX_MESSAGES = 10;

    public static void main(String[] args) throws InterruptedException {
        Topology topology = new LocalTopology("local", ThreadingPolicies.newGreenThreadingPolicy());
        
        Address pingAddress = topology.spawnActor(PING_ACTOR, new PingActorHandler());
        Address pongAddress = topology.spawnActor(PONG_ACTOR, new PongActorHandler(pingAddress));
        
        Actor pingActor = topology.getActor(pingAddress);  
        Actor pongActor = topology.getActor(pongAddress);    

        pingActor.link(pongActor); 
        pingActor.send(new StartMessage(pongAddress, MAX_MESSAGES));
    }
}

Now, enjoy!

Hosted by Google Code