Hello World
If you haven't done so already, see Getting Started.
For this example, we'll start simple and add more variations as we go along. And, to the extent possible, the examples will avoid shortcuts so that what you see in subsequent examples will be additive to previous examples.
We keep the configuration as simple as possible in these examples but you can find a complete description of configuration options in Sodacan Configuration.
We'll start by just looking at the Actor class and its constructor:
public class HelloWorld extends AbstractActor {
public HelloWorld(Config config, ActorId actorId) {
super(config, actorId);
}
Actors extend AbstractActor which in turn implements the Actor interface. While you have complete control over how the Actor is created, it is Sodacan that determines when it is created. See Configuration.
Next, each Message Route includes a target ActorId and a Verb. The verbs handled by a given ActorType are, by convention, defined
within the class that reacts to the Verb. You'll notice that the enum
implements the Verb
interface.
public enum Action implements Verb { DISPLAY, COUNT }
Because the values are used in messages between Actors and between Hosts, it is a good idea to keep the enum names stable over time to avoid confusion. Adding additional names to the list is fine.
Next, we look at the decision making around processing a given message:
@Override
public Stage processMessage() {
return switch(inbound.getVerb()) {
case Action.DISPLAY -> display(inbound);
case Action.COUNT -> count(inbound);
default -> super.processMessage();
};
}
One thing you might notice if you followed the example in Getting Started is
that the processMessage
method here is different and a bit more complex than the prior process message.
While both work, the style used here makes it easy to add additional inbound message types.
This example uses the new switch
expression syntax.
It also separates the decision making at the center of this actor from the methods that actually carry out the Some key points to keep in mind as we go along:
- Each instance of an Actor executes in its own thread. So, as long as you don't access shared resources,
you don't need to worry about concurrency. If you do, that will be discussed when we get to
Host-Bound Actors
. - When a message arrives and is ready to process, Sodacan puts it into a local field called inbound which is accessible to your Actor class. Consider this field and its contents immutable.
processMessage
must return aStage
object which contains any outbound messages resulting from the inbound message event.- The initial configuration uses short integer message and actor id numbers to make it easy for training and debugging. The id's used in production are usually UUIDs or similar.
Here is yet another approach that you may find useful. This one exploits enum
methods.
If the inbound message contains more routes in its route stack, you must add the essence of the inbound message to the Stage so that the message can be forwarded to the next target route. It is advised to always add (forward) the inbound message to the Stage. If the Route Stack is empty, Sodacan will ignore the message. However, if the message does have more routes available and the Message is not forwarded to the Stage, an error will be thrown. More details in Stage.