Event Sourcing - complex aggregate design - java

I have following code specification sample that is modelling image inside Photoshop.
Image is given with PhotoshopImage. Every image has Layers which is an object that holds all layers that an image is made of and in my case it contains only two layers - first is solid layer (instance of DefaultLayer) and second one is transparent layer (instance of NotifiableLayer). Whenever DefaultLayer is updated, we have also to update NotifiableLayer that is listening to changes on DefaultLayer (that is below), so that it can update itself (like when you update some black pixel on layer below, then transparent layer with 50% opacity that is on top of that lower layer will show that pixel in gray color).
Implementation of this is given as:
public class ES2 {
public static void main(String[] args) {
PhotoshopImage image = new PhotoshopImage();
//draw ine black pixel at position 1,1 in layer 1 (top transparent layer)
DrawOneBlackPixelCommand command1 = new DrawOneBlackPixelCommand(1,1,new Coordinates(1,1));
image.drawOneBlackPixel(command1);
//draw one black pixel at position 0,0 in layer 0 (bottom solid layer)
//this command will also affect transparent layer 1 via callback
DrawOneBlackPixelCommand command2 = new DrawOneBlackPixelCommand(1,0,new Coordinates(0,0));
image.drawOneBlackPixel(command2);
int[][] imagePixels = image.getImagePixels();
//[2, 0]
//[0, 1]
System.out.println(Arrays.toString(imagePixels[0]));
System.out.println(Arrays.toString(imagePixels[1]));
}
}
record DrawOneBlackPixelCommand(
int imageId,
int layerType,
Coordinates pixelCoordinates
){}
record Coordinates(int x, int y){}
class PhotoshopImage{
Integer imageId = 1;
String imageName = "someName";
LocalDateTime dateTime = LocalDateTime.now();
Layers layers;
PhotoshopImage(){
layers = new Layers();
}
void drawOneBlackPixel(DrawOneBlackPixelCommand command){
if(LocalDateTime.now().isBefore(dateTime)){
throw new DrawingPixelTimeExpiredException();
}
layers.drawOneBlackPixel(command.layerType(), command.pixelCoordinates());
}
int[][] getImagePixels(){
return layers.getVisibleLayerPixels();
}
class DrawingPixelTimeExpiredException extends RuntimeException{}
}
class Layers{
Set<NotifiableLayer> notifiableLayerObservers = new HashSet<>();
NavigableMap<Integer, Layer> layers = new TreeMap<>();
Layers(){
DefaultLayer solid = new DefaultLayer();
NotifiableLayer transparent = new NotifiableLayer();
layers.put(0, solid);
layers.put(1, transparent);
notifiableLayerObservers.add(transparent);
}
void drawOneBlackPixel(int layerType, Coordinates pixelCoordinates){
if(!layers.containsKey(layerType)){
throw new LayerDoesNotExistException();
}
Layer change = layers.get(layerType);
change.drawOneBlackPixel(pixelCoordinates);
notifiableLayerObservers.forEach(l -> l.notifyLayer(change, pixelCoordinates));
}
public int[][] getVisibleLayerPixels() {
return layers.lastEntry().getValue().getLayerPixels();
}
class LayerDoesNotExistException extends RuntimeException{}
}
interface Layer{
void drawOneBlackPixel(Coordinates coordinates);
int[][] getLayerPixels();
}
class DefaultLayer implements Layer{
int[][] pixels = new int[][]{{0,0},{0,0}};
#Override
public void drawOneBlackPixel(Coordinates c) {
pixels[c.x()][c.y()] = 1;
}
#Override
public int[][] getLayerPixels() {
return pixels;
}
}
class NotifiableLayer implements Layer{
int[][] pixels = new int[][]{{0,0},{0,0}};
void notifyLayer(Layer changed, Coordinates c){
//if it is not this layer, then it is layer below (solid layer)
if(changed!=this){
int pixelInLayerBelow = changed.getLayerPixels()[c.x()][c.y()];
syncPixelWithLayerBelow(pixelInLayerBelow, c);
}
}
private void syncPixelWithLayerBelow(int pixelBelow, Coordinates c){
pixels[c.x()][c.y()] = pixelBelow + 1;
}
#Override
public void drawOneBlackPixel(Coordinates c) {
pixels[c.x()][c.y()] = 1;
}
#Override
public int[][] getLayerPixels() {
return pixels;
}
}
Now, this is implemented as mutable state objects (that is - it is not using event sourcing). Whatever manual about event sourcing that I read, it is based only on some super-simple examples.
In my case - I do not know how to create events OneBlackPixelDrawnEvent (one way is in updated answer below, but it looks too complex for the benefits ES brings) - that should be result of these 2 operations in the code, and how to apply those events - should it be applied in PhotoshopImage, or should each layer be in charge of updating part of its state? How to forward those events from PhotoshopImage aggregate to Layers and further down?
UPDATE - Example of one way to implement using event sourcing
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
public class ES2 {
public static void main(String[] args) {
PhotoshopImage image = new PhotoshopImage();
//draw ine black pixel at position 1,1 in layer 1 (top transparent layer)
DrawOneBlackPixelCommand command1 = new DrawOneBlackPixelCommand(1,1,new Coordinates(1,1));
List<Event> events1 = image.drawOneBlackPixel(command1);
//[OneBlackPixelDrawnEvent[layerType=1, pixelCoordinates=Coordinates[x=1, y=1], pixelValue=1]]
System.out.println(events1);
//draw one black pixel at position 0,0 in layer 0 (bottom solid layer)
//this command will also affect transparent layer 1 via callback
DrawOneBlackPixelCommand command2 = new DrawOneBlackPixelCommand(1,0,new Coordinates(0,0));
List<Event> events2 = image.drawOneBlackPixel(command2);
//[OneBlackPixelDrawnEvent[layerType=0, pixelCoordinates=Coordinates[x=0, y=0], pixelValue=1], LayerSyncedEvent[layerType=1, pixelCoordinates=Coordinates[x=0, y=0], pixelValue=2]]
System.out.println(events2);
int[][] imagePixels = image.getImagePixels();
//[2, 0]
//[0, 1]
System.out.println(Arrays.toString(imagePixels[0]));
System.out.println(Arrays.toString(imagePixels[1]));
}
}
interface Event{}
record DrawOneBlackPixelCommand(
int imageId,
int layerType,
Coordinates pixelCoordinates
){}
record Coordinates(int x, int y){}
record OneBlackPixelDrawnEvent(
Integer layerType,
Coordinates pixelCoordinates,
Integer pixelValue
) implements Event{}
class PhotoshopImage{
Integer imageId = 1;
String imageName = "someName";
LocalDateTime dateTime = LocalDateTime.now();
Layers layers;
PhotoshopImage(){
layers = new Layers();
}
List<Event> drawOneBlackPixel(DrawOneBlackPixelCommand command){
if(LocalDateTime.now().isBefore(dateTime)){
throw new DrawingPixelTimeExpiredException();
}
List<Event> events = layers.drawOneBlackPixel(command.layerType(), command.pixelCoordinates());
apply(events); //Only here we can update state of this aggregate, so it is not updated twice
return events;
}
void apply(List<Event> events){
layers.apply(events);
}
int[][] getImagePixels(){
return layers.getVisibleLayerPixels();
}
class DrawingPixelTimeExpiredException extends RuntimeException{}
}
class Layers{
Map<Integer, NotifiableLayer> notifiableLayerObservers = new HashMap<>();
NavigableMap<Integer, Layer> layers = new TreeMap<>();
Layers(){
DefaultLayer solid = new DefaultLayer();
NotifiableLayer transparent = new NotifiableLayer();
layers.put(0, solid);
layers.put(1, transparent);
notifiableLayerObservers.put(1, transparent);
}
List<Event> drawOneBlackPixel(int layerType, Coordinates pixelCoordinates){
if(!layers.containsKey(layerType)){
throw new LayerDoesNotExistException();
}
Layer change = layers.get(layerType);
OneBlackPixelDrawnEvent event = change.drawOneBlackPixel(pixelCoordinates);
//Here, I have to add layerType, since it is a missing info on event!
OneBlackPixelDrawnEvent updatedEvent = new OneBlackPixelDrawnEvent(layerType, event.pixelCoordinates(), event.pixelValue());
List<LayerSyncedEvent> syncedEvents = notifiableLayerObservers.entrySet().stream()
.map(en ->
en.getValue()
.notifyLayer(change, updatedEvent)
//Here we have to re-pack event, since it is missing some info that can be
//filled only on this level
.map(e -> new LayerSyncedEvent(en.getKey(), e.pixelCoordinates(), e.pixelValue()))
)
.flatMap(Optional::stream)
.collect(Collectors.toList());
List<Event> results = new ArrayList<>();
results.add(updatedEvent);
results.addAll(syncedEvents);
//apply(results); we still cannot apply here, since applying in aggregate root would apply twice!
return results;
}
public void apply(List<Event> events){
for(Event e : events){
if(e instanceof LayerSyncedEvent ev){
layers.get(ev.layerType()).apply(ev);
}
if(e instanceof OneBlackPixelDrawnEvent ev){
layers.get(ev.layerType()).apply(ev);
}
}
}
public int[][] getVisibleLayerPixels() {
return layers.lastEntry().getValue().getLayerPixels();
}
class LayerDoesNotExistException extends RuntimeException{}
}
interface Layer{
OneBlackPixelDrawnEvent drawOneBlackPixel(Coordinates coordinates);
int[][] getLayerPixels();
<T extends Event> void apply(T e);
}
class DefaultLayer implements Layer{
int[][] pixels = new int[][]{{0,0},{0,0}};
#Override
public OneBlackPixelDrawnEvent drawOneBlackPixel(Coordinates c) {
OneBlackPixelDrawnEvent event = new OneBlackPixelDrawnEvent(null, c, 1);
//apply(event); ! Since applying in aggregate root - cannot apply here!
return event;
}
#Override
public int[][] getLayerPixels() {
return pixels;
}
#Override
public <T extends Event> void apply(T e) {
if(e instanceof OneBlackPixelDrawnEvent ev){
Coordinates c = ev.pixelCoordinates();
pixels[c.x()][c.y()] = ev.pixelValue();
}
}
}
record LayerSyncedEvent(
Integer layerType,
Coordinates pixelCoordinates,
Integer pixelValue
) implements Event{}
class NotifiableLayer implements Layer{
int[][] pixels = new int[][]{{0,0},{0,0}};
Optional<LayerSyncedEvent> notifyLayer(Layer changed, OneBlackPixelDrawnEvent event){
//if it is not this layer, then it is layer below (solid layer)
if(changed!=this){
Coordinates c = event.pixelCoordinates();
//Since layer is not updated anymore in-place, we have to take changes from event!
//int pixelInLayerBelow = changed.getLayerPixels()[c.x()][c.y()];
int pixelInLayerBelow = event.pixelValue();
return Optional.of(syncPixelWithLayerBelow(pixelInLayerBelow, c));
}
return Optional.empty();
}
private LayerSyncedEvent syncPixelWithLayerBelow(int pixelBelow, Coordinates c){
LayerSyncedEvent event = new LayerSyncedEvent(null, c, pixelBelow + 1);
//apply(event); ! Since applying in aggregate root - cannot apply here!
return event;
}
#Override
public OneBlackPixelDrawnEvent drawOneBlackPixel(Coordinates c) {
OneBlackPixelDrawnEvent event = new OneBlackPixelDrawnEvent(null, c, 1);
//apply(event); ! Since applying in aggregate root - cannot apply here!
return event;
}
#Override
public int[][] getLayerPixels() {
return pixels;
}
#Override
public <T extends Event> void apply(T e) {
if(e instanceof LayerSyncedEvent ev){
Coordinates c = ev.pixelCoordinates();
pixels[c.x()][c.y()] = ev.pixelValue();
}
if(e instanceof OneBlackPixelDrawnEvent ev){
Coordinates c = ev.pixelCoordinates();
pixels[c.x()][c.y()] = ev.pixelValue();
}
}
}
I just updated example here with one way to implement Aggregate root, with methods that return events. I guess this is one possible implementation - but look how much complex this is now; even this simple example - increased 2x in complexity. Am I doing something wrong, or is this just not that easy to do in event-sourced system?

Although debatable, I'd argue whether "photoshopping" is a domain you'd want to implement with paradigms like DDD, CQRS and Event Sourcing in mind. As to some extend mentioned by VoicOfUnreason, sometimes the work doesn't out way the benefits; you might just have picked such a domain for which it isn't feasible.
Regardless, let me try to give some guidance to your questions and the snippets you've shared. First thing I'd like to emphasize on, is returning the List<Event> objects from your command handlers. Although reasonable in home grown DDD/CQRS/ES systems, this is not something you'd do with an Axon Framework based application (which I assume you are using through the axon tag).
Command handlers should only share whether an operation was successful, unsuccessful, or the identifier of newly created entities. That's it.
Another pointer worth sharing, is the placement of the Command Handler. You have currently designed it to start at the PhotoshopImage. However commands can perfectly well be targeted towards an exact entity within the Aggregate. From a definition stance this is also fine, as:
The Aggregate is a group of associated objects which in regard to data changes act as a single unit. There is a single reference to the Aggregate, called the Aggregate Root. Lastly, consistency rules apply within the boundaries of the Aggregate.
So, the entire Aggregate consists (in your sample) out of a PhotoshopImage and a list of Layer entities. The PhotoshopImage is your Aggregate Root in this case. Taking the "single reference" argument, this means commands would always flow through the Aggregate Root, which thus is the PhotoshopImage. This however doesn't make the PhotoshopImage entity the object in charge of deciding upon handling the command.
From the looks of the implementation, and if I follow your description correctly, there is a necessity to handle the operation in the root to delegate the operations to all layers. This would indeed opt for the command handler as it is situated right now.
It is upon the publication of events where you can greatly simplify things. Note though that I am basing myself on Axon Framework in this case, which I am assuming is fair since the axon tag is being used. Right now, it's the PhotoshopImage which publishes the events. I would have each of your Layers publish it's own OneBlackPixelDrawnEvent instead. When you would be using Event Sourcing, the publication and handling of such an event within the boundary of the aggregate will have precedence over furthering the command handling operation.
Thus, there would be no need whatsoever to invoke notifiableLayerObservers in your sample to correctly notify all Layers. This should simply be part of the CQRS/DDD/ES framework you are using, which Axon Framework would thus do for you out of the box. Simply mark a method as an #EventSourcingHandler and Axon Framework will not to invoke all event sourcing handlers for a given event, regardless of whether they reside in the Aggregate Root or any of the entities.
Following that route, you can adjust the right portions of state per entity when they are handling the (in your scenario) OneBlackPixelDrawnEvent.
As stated earlier, I am assuming you are using a framework like Axon in this case. Or otherwise that you have the correctly implementation layering in place to achieve the same. Having such a set up will allow you to get away with all the custom routing information you are currently doing in your Command Handling functions.
Last note, I am making assumption on a Domain I am not familiar with. If anything this hurts when using the above mentioned approach, make sure to place a comment so we can discuss it further. In the meantime, I hope this helps you out!

Event Sourcing is based on the assumption that the system records events happening on Aggregate roots. In your case, when a Layer is updated, the Image containing it will append an event to an internal collection. Something like LayerUpdated... although it's considered good practise to give meaningful names to events.
When all the operations (aka Commands) have been executed, the system starts persisting those events and for each one, it will also broadcast a notification.
Now you could either have each NotifiableLayer listening to specific notifications, or you can have a separate service who can do that and update all the NotifiableLayer instances accordingly. I would go for the service: I don't really like the idea of Domain Entities listening to notifications.

Related

Akka stream - limiting Flow rate without introducing delay

I'm working with Akka (version 2.4.17) to build an observation Flow in Java (let's say of elements of type <T> to stay generic).
My requirement is that this Flow should be customizable to deliver a maximum number of observations per unit of time as soon as they arrive. For instance, it should be able to deliver at most 2 observations per minute (the first that arrive, the rest can be dropped).
I looked very closely to the Akka documentation, and in particular this page which details the built-in stages and their semantics.
So far, I tried the following approaches.
With throttle and shaping() mode (to not close the stream when the limit is exceeded):
Flow.of(T.class)
.throttle(2,
new FiniteDuration(1, TimeUnit.MINUTES),
0,
ThrottleMode.shaping())
With groupedWith and an intermediary custom method:
final int nbObsMax = 2;
Flow.of(T.class)
.groupedWithin(Integer.MAX_VALUE, new FiniteDuration(1, TimeUnit.MINUTES))
.map(list -> {
List<T> listToTransfer = new ArrayList<>();
for (int i = list.size()-nbObsMax ; i>0 && i<list.size() ; i++) {
listToTransfer.add(new T(list.get(i)));
}
return listToTransfer;
})
.mapConcat(elem -> elem) // Splitting List<T> in a Flow of T objects
Previous approaches give me the correct number of observations per unit of time but these observations are retained and only delivered at the end of the time window (and therefore there is an additional delay).
To give a more concrete example, if the following observations arrives into my Flow:
[Obs1 t=0s] [Obs2 t=45s] [Obs3 t=47s] [Obs4 t=121s] [Obs5 t=122s]
It should only output the following ones as soon as they arrive (processing time can be neglected here):
Window 1: [Obs1 t~0s] [Obs2 t~45s]
Window 2: [Obs4 t~121s] [Obs5 t~122s]
Any help will be appreciated, thanks for reading my first StackOverflow post ;)
I cannot think of a solution out of the box that does what you want. Throttle will emit in a steady stream because of how it is implemented with the bucket model, rather than having a permitted lease at the start of every time period.
To get the exact behavior you are after you would have to create your own custom rate-limit stage (which might not be that hard). You can find the docs on how to create custom stages here: http://doc.akka.io/docs/akka/2.5.0/java/stream/stream-customize.html#custom-linear-processing-stages-using-graphstage
One design that could work is having an allowance counter saying how many elements that can be emitted that you reset every interval, for every incoming element you subtract one from the counter and emit, when the allowance used up you keep pulling upstream but discard the elements rather than emit them. Using TimerGraphStageLogic for GraphStageLogic allows you to set a timed callback that can reset the allowance.
I think this is exactly what you need: http://doc.akka.io/docs/akka/2.5.0/java/stream/stream-cookbook.html#Globally_limiting_the_rate_of_a_set_of_streams
Thanks to the answer of #johanandren, I've successfully implemented a custom time-based GraphStage that meets my requirements.
I post the code below, if anyone is interested:
import akka.stream.Attributes;
import akka.stream.FlowShape;
import akka.stream.Inlet;
import akka.stream.Outlet;
import akka.stream.stage.*;
import scala.concurrent.duration.FiniteDuration;
public class CustomThrottleGraphStage<A> extends GraphStage<FlowShape<A, A>> {
private final FiniteDuration silencePeriod;
private int nbElemsMax;
public CustomThrottleGraphStage(int nbElemsMax, FiniteDuration silencePeriod) {
this.silencePeriod = silencePeriod;
this.nbElemsMax = nbElemsMax;
}
public final Inlet<A> in = Inlet.create("TimedGate.in");
public final Outlet<A> out = Outlet.create("TimedGate.out");
private final FlowShape<A, A> shape = FlowShape.of(in, out);
#Override
public FlowShape<A, A> shape() {
return shape;
}
#Override
public GraphStageLogic createLogic(Attributes inheritedAttributes) {
return new TimerGraphStageLogic(shape) {
private boolean open = false;
private int countElements = 0;
{
setHandler(in, new AbstractInHandler() {
#Override
public void onPush() throws Exception {
A elem = grab(in);
if (open || countElements >= nbElemsMax) {
pull(in); // we drop all incoming observations since the rate limit has been reached
}
else {
if (countElements == 0) { // we schedule the next instant to reset the observation counter
scheduleOnce("resetCounter", silencePeriod);
}
push(out, elem); // we forward the incoming observation
countElements += 1; // we increment the counter
}
}
});
setHandler(out, new AbstractOutHandler() {
#Override
public void onPull() throws Exception {
pull(in);
}
});
}
#Override
public void onTimer(Object key) {
if (key.equals("resetCounter")) {
open = false;
countElements = 0;
}
}
};
}
}

Which state machine design to use if your target state is not the next one?

I've been reading up on State Machines since its likely I need to use for my next project. Most examples I find online show how to go from StateA to StateB. But what if your next desired state is not an adjacent state? Are there any common patterns/practices to achieve this? Ideally in Java, but I can read other programming languages just as well.
# Example States
WakeUp->Get Dressed->Get Car Keys->Get in Car->Drive to Work->Work
Current State: Get in Car
Problems to solve
# Scenario 1: Desired State == Work
Forgot car keys, so you have to return to previous state and then move forward in states again.
# Scenario 2: Desired State == Work
Have car keys, so move forward in states to get to Desired State.
It's very likely that State Machine may not solve this problem elegantly and I just need to hand-craft the logic, I don't mind, but thought I'd follow a common design pattern to help others understand it.
From the example above, I do not need to worry about 'internal' states, which is also true for the project I'm tackling; just in case that makes a difference in possible solutions.
Here is a simple way to define a state machine.
Define in an enum all the states that you want.
enum StateType {
WAKE_UP, GET_DRESSED, GET_CAR_KEYS, GET_IN_CAR, DRIVE_TO_WORK, WORK
}
Have a statemachine which controls states, and a state interface which performs an action on the statemachine. The state then returns the next state to go to.
interface State {
StateType next(StateMachine sm);
}
Implement this state for multiple types
class GetInCarState implements State {
#Override
public StateType next(StateMachine sm) {
if (sm.hasKeys()) {
return StateType.DRIVE_TO_WORK;
}
return StateType.GET_CAR_KEYS;
}
}
Now define the State Machine
class StateMachine {
private Map<StateType, State> states = new HashMap<StateType, State>() {{
put(StateType.WAKE_UP, new WakeUpState());
put(StateType.GET_DRESSED, new GetDressedState());
put(StateType.GET_CAR_KEYS, new GetCarKeysState());
put(StateType.GET_IN_CAR, new GetInCarState());
put(StateType.DRIVE_TO_WORK, new DriveToWorkState());
put(StateType.WORK, new WorkState());
}};
private StateType currentState = StateType.WAKE_UP;
private boolean hasCarKeys;
public boolean hasKeys() {
return hasCarKeys;
}
public void setHasKeys(boolean hasKeys) {
hasCarKeys = hasKeys;
}
public void update() {
currentState = states.get(currentState).next(this);
}
}

Object-Oriented design simulating a process with states [duplicate]

I have something to do for work and I need your help.
We want to implement a FSM - Finite State Machine, to identify char sequence(like: A, B, C, A, C), and tell if it accepted.
We think to implement three classes: State, Event and Machine.
The state class presents a node in the FSM, we thought to implement it with State design pattern, every node will extend from the abstract class state and every class would handle different types of events and indicate transitions to a new state. Is it good idea in your opinion?
Second thing, we don't know how to save all the transitions. Again we thought to implement it with some kind of map, that hold the starting point and gets some kind of vector with the next states, but I'm not sure thats a good idea.
I would be happy to get some ideas of how to implement it or maybe you can give me some starting points.
How should I save the FSM, meaning how should I build the tree at the beginning of the program?
I googled it and found a lot of examples but nothing that helps me.
Thanks a lot.
The heart of a state machine is the transition table, which takes a state and a symbol (what you're calling an event) to a new state. That's just a two-index array of states. For sanity and type safety, declare the states and symbols as enumerations. I always add a "length" member in some way (language-specific) for checking array bounds. When I've hand-coded FSM's, I format the code in row and column format with whitespace fiddling. The other elements of a state machine are the initial state and the set of accepting states. The most direct implementation of the set of accepting states is an array of booleans indexed by the states. In Java, however, enumerations are classes, and you can specify an argument "accepting" in the declaration for each enumerated value and initialize it in the constructor for the enumeration.
For the machine type, you can write it as a generic class. It would take two type arguments, one for the states and one for the symbols, an array argument for the transition table, a single state for the initial. The only other detail (though it's critical) is that you have to call Enum.ordinal() to get an integer suitable for indexing the transition array, since you there's no syntax for directly declaring an array with a enumeration index (though there ought to be).
To preempt one issue, EnumMap won't work for the transition table, because the key required is a pair of enumeration values, not a single one.
enum State {
Initial( false ),
Final( true ),
Error( false );
static public final Integer length = 1 + Error.ordinal();
final boolean accepting;
State( boolean accepting ) {
this.accepting = accepting;
}
}
enum Symbol {
A, B, C;
static public final Integer length = 1 + C.ordinal();
}
State transition[][] = {
// A B C
{
State.Initial, State.Final, State.Error
}, {
State.Final, State.Initial, State.Error
}
};
EasyFSM is a dynamic Java Library which can be used to implement an FSM.
You can find documentation for the same at :
Finite State Machine in Java
Also, you can download the library at :
Java FSM Library : DynamicEasyFSM
You can implement Finite State Machine in two different ways.
Option 1:
Finite State machine with a pre-defined workflow : Recommended if you know all states in advance and state machine is almost fixed without any changes in future
Identify all possible states in your application
Identify all the events in your application
Identify all the conditions in your application, which may lead state transition
Occurrence of an event may cause transitions of state
Build a finite state machine by deciding a workflow of states & transitions.
e.g If an event 1 occurs at State 1, the state will be updated and machine state may still be in state 1.
If an event 2 occurs at State 1, on some condition evaluation, the system will move from State 1 to State 2
This design is based on State and Context patterns.
Have a look at Finite State Machine prototype classes.
Option 2:
Behavioural trees: Recommended if there are frequent changes to state machine workflow. You can dynamically add new behaviour without breaking the tree.
The base Task class provides a interface for all these tasks, the leaf tasks are the ones just mentioned, and the parent tasks are the interior nodes that decide which task to execute next.
The Tasks have only the logic they need to actually do what is required of them, all the decision logic of whether a task has started or not, if it needs to update, if it has finished with success, etc. is grouped in the TaskController class, and added by composition.
The decorators are tasks that “decorate” another class by wrapping over it and giving it additional logic.
Finally, the Blackboard class is a class owned by the parent AI that every task has a reference to. It works as a knowledge database for all the leaf tasks
Have a look at this article by Jaime Barrachina Verdia for more details
Hmm, I would suggest that you use Flyweight to implement the states. Purpose: Avoid the memory overhead of a large number of small objects. State machines can get very, very big.
http://en.wikipedia.org/wiki/Flyweight_pattern
I'm not sure that I see the need to use design pattern State to implement the nodes. The nodes in a state machine are stateless. They just match the current input symbol to the available transitions from the current state. That is, unless I have entirely forgotten how they work (which is a definite possiblilty).
If I were coding it, I would do something like this:
interface FsmNode {
public boolean canConsume(Symbol sym);
public FsmNode consume(Symbol sym);
// Other methods here to identify the state we are in
}
List<Symbol> input = getSymbols();
FsmNode current = getStartState();
for (final Symbol sym : input) {
if (!current.canConsume(sym)) {
throw new RuntimeException("FSM node " + current + " can't consume symbol " + sym);
}
current = current.consume(sym);
}
System.out.println("FSM consumed all input, end state is " + current);
What would Flyweight do in this case? Well, underneath the FsmNode there would probably be something like this:
Map<Integer, Map<Symbol, Integer>> fsm; // A state is an Integer, the transitions are from symbol to state number
FsmState makeState(int stateNum) {
return new FsmState() {
public FsmState consume(final Symbol sym) {
final Map<Symbol, Integer> transitions = fsm.get(stateNum);
if (transisions == null) {
throw new RuntimeException("Illegal state number " + stateNum);
}
final Integer nextState = transitions.get(sym); // May be null if no transition
return nextState;
}
public boolean canConsume(final Symbol sym) {
return consume(sym) != null;
}
}
}
This creates the State objects on a need-to-use basis, It allows you to use a much more efficient underlying mechanism to store the actual state machine. The one I use here (Map(Integer, Map(Symbol, Integer))) is not particulary efficient.
Note that the Wikipedia page focuses on the cases where many somewhat similar objects share the similar data, as is the case in the String implementation in Java. In my opinion, Flyweight is a tad more general, and covers any on-demand creation of objects with a short life span (use more CPU to save on a more efficient underlying data structure).
Consider the easy, lightweight Java library EasyFlow. From their docs:
With EasyFlow you can:
implement complex logic but keep your code simple and clean
handle asynchronous calls with ease and elegance
avoid concurrency by using event-driven programming approach
avoid StackOverflow error by avoiding recursion
simplify design, programming and testing of complex java applications
I design & implemented a simple finite state machine example with java.
IFiniteStateMachine: The public interface to manage the finite state machine
such as add new states to the finite state machine or transit to next states by specific actions.
interface IFiniteStateMachine {
void setStartState(IState startState);
void setEndState(IState endState);
void addState(IState startState, IState newState, Action action);
void removeState(String targetStateDesc);
IState getCurrentState();
IState getStartState();
IState getEndState();
void transit(Action action);
}
IState: The public interface to get state related info
such as state name and mappings to connected states.
interface IState {
// Returns the mapping for which one action will lead to another state
Map<String, IState> getAdjacentStates();
String getStateDesc();
void addTransit(Action action, IState nextState);
void removeTransit(String targetStateDesc);
}
Action: the class which will cause the transition of states.
public class Action {
private String mActionName;
public Action(String actionName) {
mActionName = actionName;
}
String getActionName() {
return mActionName;
}
#Override
public String toString() {
return mActionName;
}
}
StateImpl: the implementation of IState. I applied data structure such as HashMap to keep Action-State mappings.
public class StateImpl implements IState {
private HashMap<String, IState> mMapping = new HashMap<>();
private String mStateName;
public StateImpl(String stateName) {
mStateName = stateName;
}
#Override
public Map<String, IState> getAdjacentStates() {
return mMapping;
}
#Override
public String getStateDesc() {
return mStateName;
}
#Override
public void addTransit(Action action, IState state) {
mMapping.put(action.toString(), state);
}
#Override
public void removeTransit(String targetStateDesc) {
// get action which directs to target state
String targetAction = null;
for (Map.Entry<String, IState> entry : mMapping.entrySet()) {
IState state = entry.getValue();
if (state.getStateDesc().equals(targetStateDesc)) {
targetAction = entry.getKey();
}
}
mMapping.remove(targetAction);
}
}
FiniteStateMachineImpl: Implementation of IFiniteStateMachine. I use ArrayList to keep all the states.
public class FiniteStateMachineImpl implements IFiniteStateMachine {
private IState mStartState;
private IState mEndState;
private IState mCurrentState;
private ArrayList<IState> mAllStates = new ArrayList<>();
private HashMap<String, ArrayList<IState>> mMapForAllStates = new HashMap<>();
public FiniteStateMachineImpl(){}
#Override
public void setStartState(IState startState) {
mStartState = startState;
mCurrentState = startState;
mAllStates.add(startState);
// todo: might have some value
mMapForAllStates.put(startState.getStateDesc(), new ArrayList<IState>());
}
#Override
public void setEndState(IState endState) {
mEndState = endState;
mAllStates.add(endState);
mMapForAllStates.put(endState.getStateDesc(), new ArrayList<IState>());
}
#Override
public void addState(IState startState, IState newState, Action action) {
// validate startState, newState and action
// update mapping in finite state machine
mAllStates.add(newState);
final String startStateDesc = startState.getStateDesc();
final String newStateDesc = newState.getStateDesc();
mMapForAllStates.put(newStateDesc, new ArrayList<IState>());
ArrayList<IState> adjacentStateList = null;
if (mMapForAllStates.containsKey(startStateDesc)) {
adjacentStateList = mMapForAllStates.get(startStateDesc);
adjacentStateList.add(newState);
} else {
mAllStates.add(startState);
adjacentStateList = new ArrayList<>();
adjacentStateList.add(newState);
}
mMapForAllStates.put(startStateDesc, adjacentStateList);
// update mapping in startState
for (IState state : mAllStates) {
boolean isStartState = state.getStateDesc().equals(startState.getStateDesc());
if (isStartState) {
startState.addTransit(action, newState);
}
}
}
#Override
public void removeState(String targetStateDesc) {
// validate state
if (!mMapForAllStates.containsKey(targetStateDesc)) {
throw new RuntimeException("Don't have state: " + targetStateDesc);
} else {
// remove from mapping
mMapForAllStates.remove(targetStateDesc);
}
// update all state
IState targetState = null;
for (IState state : mAllStates) {
if (state.getStateDesc().equals(targetStateDesc)) {
targetState = state;
} else {
state.removeTransit(targetStateDesc);
}
}
mAllStates.remove(targetState);
}
#Override
public IState getCurrentState() {
return mCurrentState;
}
#Override
public void transit(Action action) {
if (mCurrentState == null) {
throw new RuntimeException("Please setup start state");
}
Map<String, IState> localMapping = mCurrentState.getAdjacentStates();
if (localMapping.containsKey(action.toString())) {
mCurrentState = localMapping.get(action.toString());
} else {
throw new RuntimeException("No action start from current state");
}
}
#Override
public IState getStartState() {
return mStartState;
}
#Override
public IState getEndState() {
return mEndState;
}
}
example:
public class example {
public static void main(String[] args) {
System.out.println("Finite state machine!!!");
IState startState = new StateImpl("start");
IState endState = new StateImpl("end");
IFiniteStateMachine fsm = new FiniteStateMachineImpl();
fsm.setStartState(startState);
fsm.setEndState(endState);
IState middle1 = new StateImpl("middle1");
middle1.addTransit(new Action("path1"), endState);
fsm.addState(startState, middle1, new Action("path1"));
System.out.println(fsm.getCurrentState().getStateDesc());
fsm.transit(new Action(("path1")));
System.out.println(fsm.getCurrentState().getStateDesc());
fsm.addState(middle1, endState, new Action("path1-end"));
fsm.transit(new Action(("path1-end")));
System.out.println(fsm.getCurrentState().getStateDesc());
fsm.addState(endState, middle1, new Action("path1-end"));
}
}
Full example on Github
Well this is an old question but while nobody mentioned here, I will advice to check two existing frameworks before you implement you own State Machines.
One is Spring State Machine most of you are familiar with Spring framework, which allow us to use several features of Spring like dependency injection and everything else that Spring can offer.
It is really great for modelling the lifecycle of an Apparat, with states like INITIALIZING, STARTED, ERROR, RECOVERING, SHUTTINGDOWN, etc.. but I see lots of people are trying to model a Shopping Chart, a Reservation System with it, the memory footprint a Spring State Machine is relatively big to model millions of Shopping Charts or Reservations.
One other disadvantage, Spring State Machine, while has a capability to persist itself for long running processes but it does not have any mechanism to adapt to changes in these processes, if you persist a process and you have to recover it lets say 10 days later with a change occurred in your business process because of new software release / requirement, you have no built in means to deal with it.
I have several blogs, blog1 blog2, demonstrating how you can program Spring State Machine, specially model driven way, if you want to check it.
Mainly because the disadvantages I mentioned, I advice you to look another framework first, Akka FSM (Finite State Machine) which is more fitting with its low memory footprint to have millions and millions of instances and has a capability to adapt changing long running processes.
Now you can develop with Akka framework with Java but believe me because of some missing language elements, you don't want to read the produced code, Scala is a much more fitting language to develop with Akka. Now I hear you saying Scala is too complex, I can't convince my project leads to develop with Scala, to convince you all this is an option, I developed a Proof of Concept application using a Java/Scala hybrid with all Scala Akka Finite State Machine code generated from an UML model, if you want to check it out here the links to the blogs, blog3 blog4.
I hope this information would help you.
Here is a SUPER SIMPLE implementation/example of a FSM using just "if-else"s which avoids all of the above subclassing answers (taken from Using Finite State Machines for Pattern Matching in Java, where he is looking for a string which ends with "#" followed by numbers followed by "#"--see state graph here):
public static void main(String[] args) {
String s = "A1#312#";
String digits = "0123456789";
int state = 0;
for (int ind = 0; ind < s.length(); ind++) {
if (state == 0) {
if (s.charAt(ind) == '#')
state = 1;
} else {
boolean isNumber = digits.indexOf(s.charAt(ind)) != -1;
if (state == 1) {
if (isNumber)
state = 2;
else if (s.charAt(ind) == '#')
state = 1;
else
state = 0;
} else if (state == 2) {
if (s.charAt(ind) == '#') {
state = 3;
} else if (isNumber) {
state = 2;
} else if (s.charAt(ind) == '#')
state = 1;
else
state = 0;
} else if (state == 3) {
if (s.charAt(ind) == '#')
state = 1;
else
state = 0;
}
}
} //end for loop
if (state == 3)
System.out.println("It matches");
else
System.out.println("It does not match");
}
P.S: Does not answer your question directly, but shows you how to implement a FSM very easily in Java.

Instantly synchronizing two tables in Vaadin

In my Vaadin UI, I have the following scenario:
In other words, there are two tables:
a "master" table that is editable,
a "slave" table that is non-editable, but must contain the same data as the master table, however with a potentially different sort order.
The final requirement precludes the tables having the same Container (in my understanding, which might be wrong).
What I've done currently is that I attach an ItemSetChangeListener and a ValueChangeListener, and use the events to update the data accordingly.
Here's the current crude implementation (in Scala actually, but I hope it's readable enough, if not, please comment) :
class DataTableSynchronizer(val master: Table, val slave: Table) extends ItemSetChangeListener with ValueChangeListener {
def init():Unit = {
master.addItemSetChangeListener(this)
containerMaster.addListener(this.asInstanceOf[ValueChangeListener])
}
private def containerOf(t: Table) = t.getContainerDataSource().asInstanceOf[IndexedContainer]
private def containerMaster = containerOf(master)
private def containerSlave = containerOf(slave)
override def containerItemSetChange(event: ItemSetChangeEvent) {
//handling
//remove all items that have been deleted
for(toDel <- containerSlave.getItemIds().filterNot(containerMaster.containsId(_))) {
containerSlave.removeItem(toDel)
}
//add new items to the start
for(toAdd <- containerMaster.getItemIds().filterNot(containerSlave.containsId(_))) {
containerSlave.addItem(toAdd)
}
slave.validate();
}
override def valueChange(event: ValueChangeEvent) = {
updateValuesInResults()
}
private def updateValuesInResults(): Unit = {
//update all values in the "slave" table from the "master" table
for((itemData,itemResults) <- containerMaster.getItemIds().map(id => (containerMaster.getItem(id),containerSlave.getItem(id)))) {
for(propId <- itemData.getItemPropertyIds()) {
itemResults.getItemProperty(propId).asInstanceOf[Property[Any]].setValue(itemData.getItemProperty(propId).getValue().asInstanceOf[Any])
}
}
}
}
However, my problem is that I need the data to be synchronized continuously, as the user types, which is not happening due to the relevant events being sent only after some operation completes (a row is added, etc.).
How do I solve this, i.e. how do I enforce events being emitted often enough to enable continuous synchronization? The only idea I had was to use an ActionListener mapping all the keys, but that screams "abuse".
Note: I realize doing this through the server-side is less efficient, but this is not a concern in my case. However, client-side-based answers are OK as well, of course.
You can set the TextChangeEventMode of the editor to EAGER and process single keystrokes in the event listener:
TextField textField = ...;
textField.setTextChangeEventMode(TextChangeEventMode.EAGER);
textField.addTextChangeListener(new TextChangeListener() {
#Override
public void textChange(TextChangeEvent event) {
String text = event.getText();
// sync with other component
}
});

How to implement a FSM - Finite State Machine in Java

I have something to do for work and I need your help.
We want to implement a FSM - Finite State Machine, to identify char sequence(like: A, B, C, A, C), and tell if it accepted.
We think to implement three classes: State, Event and Machine.
The state class presents a node in the FSM, we thought to implement it with State design pattern, every node will extend from the abstract class state and every class would handle different types of events and indicate transitions to a new state. Is it good idea in your opinion?
Second thing, we don't know how to save all the transitions. Again we thought to implement it with some kind of map, that hold the starting point and gets some kind of vector with the next states, but I'm not sure thats a good idea.
I would be happy to get some ideas of how to implement it or maybe you can give me some starting points.
How should I save the FSM, meaning how should I build the tree at the beginning of the program?
I googled it and found a lot of examples but nothing that helps me.
Thanks a lot.
The heart of a state machine is the transition table, which takes a state and a symbol (what you're calling an event) to a new state. That's just a two-index array of states. For sanity and type safety, declare the states and symbols as enumerations. I always add a "length" member in some way (language-specific) for checking array bounds. When I've hand-coded FSM's, I format the code in row and column format with whitespace fiddling. The other elements of a state machine are the initial state and the set of accepting states. The most direct implementation of the set of accepting states is an array of booleans indexed by the states. In Java, however, enumerations are classes, and you can specify an argument "accepting" in the declaration for each enumerated value and initialize it in the constructor for the enumeration.
For the machine type, you can write it as a generic class. It would take two type arguments, one for the states and one for the symbols, an array argument for the transition table, a single state for the initial. The only other detail (though it's critical) is that you have to call Enum.ordinal() to get an integer suitable for indexing the transition array, since you there's no syntax for directly declaring an array with a enumeration index (though there ought to be).
To preempt one issue, EnumMap won't work for the transition table, because the key required is a pair of enumeration values, not a single one.
enum State {
Initial( false ),
Final( true ),
Error( false );
static public final Integer length = 1 + Error.ordinal();
final boolean accepting;
State( boolean accepting ) {
this.accepting = accepting;
}
}
enum Symbol {
A, B, C;
static public final Integer length = 1 + C.ordinal();
}
State transition[][] = {
// A B C
{
State.Initial, State.Final, State.Error
}, {
State.Final, State.Initial, State.Error
}
};
EasyFSM is a dynamic Java Library which can be used to implement an FSM.
You can find documentation for the same at :
Finite State Machine in Java
Also, you can download the library at :
Java FSM Library : DynamicEasyFSM
You can implement Finite State Machine in two different ways.
Option 1:
Finite State machine with a pre-defined workflow : Recommended if you know all states in advance and state machine is almost fixed without any changes in future
Identify all possible states in your application
Identify all the events in your application
Identify all the conditions in your application, which may lead state transition
Occurrence of an event may cause transitions of state
Build a finite state machine by deciding a workflow of states & transitions.
e.g If an event 1 occurs at State 1, the state will be updated and machine state may still be in state 1.
If an event 2 occurs at State 1, on some condition evaluation, the system will move from State 1 to State 2
This design is based on State and Context patterns.
Have a look at Finite State Machine prototype classes.
Option 2:
Behavioural trees: Recommended if there are frequent changes to state machine workflow. You can dynamically add new behaviour without breaking the tree.
The base Task class provides a interface for all these tasks, the leaf tasks are the ones just mentioned, and the parent tasks are the interior nodes that decide which task to execute next.
The Tasks have only the logic they need to actually do what is required of them, all the decision logic of whether a task has started or not, if it needs to update, if it has finished with success, etc. is grouped in the TaskController class, and added by composition.
The decorators are tasks that “decorate” another class by wrapping over it and giving it additional logic.
Finally, the Blackboard class is a class owned by the parent AI that every task has a reference to. It works as a knowledge database for all the leaf tasks
Have a look at this article by Jaime Barrachina Verdia for more details
Hmm, I would suggest that you use Flyweight to implement the states. Purpose: Avoid the memory overhead of a large number of small objects. State machines can get very, very big.
http://en.wikipedia.org/wiki/Flyweight_pattern
I'm not sure that I see the need to use design pattern State to implement the nodes. The nodes in a state machine are stateless. They just match the current input symbol to the available transitions from the current state. That is, unless I have entirely forgotten how they work (which is a definite possiblilty).
If I were coding it, I would do something like this:
interface FsmNode {
public boolean canConsume(Symbol sym);
public FsmNode consume(Symbol sym);
// Other methods here to identify the state we are in
}
List<Symbol> input = getSymbols();
FsmNode current = getStartState();
for (final Symbol sym : input) {
if (!current.canConsume(sym)) {
throw new RuntimeException("FSM node " + current + " can't consume symbol " + sym);
}
current = current.consume(sym);
}
System.out.println("FSM consumed all input, end state is " + current);
What would Flyweight do in this case? Well, underneath the FsmNode there would probably be something like this:
Map<Integer, Map<Symbol, Integer>> fsm; // A state is an Integer, the transitions are from symbol to state number
FsmState makeState(int stateNum) {
return new FsmState() {
public FsmState consume(final Symbol sym) {
final Map<Symbol, Integer> transitions = fsm.get(stateNum);
if (transisions == null) {
throw new RuntimeException("Illegal state number " + stateNum);
}
final Integer nextState = transitions.get(sym); // May be null if no transition
return nextState;
}
public boolean canConsume(final Symbol sym) {
return consume(sym) != null;
}
}
}
This creates the State objects on a need-to-use basis, It allows you to use a much more efficient underlying mechanism to store the actual state machine. The one I use here (Map(Integer, Map(Symbol, Integer))) is not particulary efficient.
Note that the Wikipedia page focuses on the cases where many somewhat similar objects share the similar data, as is the case in the String implementation in Java. In my opinion, Flyweight is a tad more general, and covers any on-demand creation of objects with a short life span (use more CPU to save on a more efficient underlying data structure).
Consider the easy, lightweight Java library EasyFlow. From their docs:
With EasyFlow you can:
implement complex logic but keep your code simple and clean
handle asynchronous calls with ease and elegance
avoid concurrency by using event-driven programming approach
avoid StackOverflow error by avoiding recursion
simplify design, programming and testing of complex java applications
I design & implemented a simple finite state machine example with java.
IFiniteStateMachine: The public interface to manage the finite state machine
such as add new states to the finite state machine or transit to next states by specific actions.
interface IFiniteStateMachine {
void setStartState(IState startState);
void setEndState(IState endState);
void addState(IState startState, IState newState, Action action);
void removeState(String targetStateDesc);
IState getCurrentState();
IState getStartState();
IState getEndState();
void transit(Action action);
}
IState: The public interface to get state related info
such as state name and mappings to connected states.
interface IState {
// Returns the mapping for which one action will lead to another state
Map<String, IState> getAdjacentStates();
String getStateDesc();
void addTransit(Action action, IState nextState);
void removeTransit(String targetStateDesc);
}
Action: the class which will cause the transition of states.
public class Action {
private String mActionName;
public Action(String actionName) {
mActionName = actionName;
}
String getActionName() {
return mActionName;
}
#Override
public String toString() {
return mActionName;
}
}
StateImpl: the implementation of IState. I applied data structure such as HashMap to keep Action-State mappings.
public class StateImpl implements IState {
private HashMap<String, IState> mMapping = new HashMap<>();
private String mStateName;
public StateImpl(String stateName) {
mStateName = stateName;
}
#Override
public Map<String, IState> getAdjacentStates() {
return mMapping;
}
#Override
public String getStateDesc() {
return mStateName;
}
#Override
public void addTransit(Action action, IState state) {
mMapping.put(action.toString(), state);
}
#Override
public void removeTransit(String targetStateDesc) {
// get action which directs to target state
String targetAction = null;
for (Map.Entry<String, IState> entry : mMapping.entrySet()) {
IState state = entry.getValue();
if (state.getStateDesc().equals(targetStateDesc)) {
targetAction = entry.getKey();
}
}
mMapping.remove(targetAction);
}
}
FiniteStateMachineImpl: Implementation of IFiniteStateMachine. I use ArrayList to keep all the states.
public class FiniteStateMachineImpl implements IFiniteStateMachine {
private IState mStartState;
private IState mEndState;
private IState mCurrentState;
private ArrayList<IState> mAllStates = new ArrayList<>();
private HashMap<String, ArrayList<IState>> mMapForAllStates = new HashMap<>();
public FiniteStateMachineImpl(){}
#Override
public void setStartState(IState startState) {
mStartState = startState;
mCurrentState = startState;
mAllStates.add(startState);
// todo: might have some value
mMapForAllStates.put(startState.getStateDesc(), new ArrayList<IState>());
}
#Override
public void setEndState(IState endState) {
mEndState = endState;
mAllStates.add(endState);
mMapForAllStates.put(endState.getStateDesc(), new ArrayList<IState>());
}
#Override
public void addState(IState startState, IState newState, Action action) {
// validate startState, newState and action
// update mapping in finite state machine
mAllStates.add(newState);
final String startStateDesc = startState.getStateDesc();
final String newStateDesc = newState.getStateDesc();
mMapForAllStates.put(newStateDesc, new ArrayList<IState>());
ArrayList<IState> adjacentStateList = null;
if (mMapForAllStates.containsKey(startStateDesc)) {
adjacentStateList = mMapForAllStates.get(startStateDesc);
adjacentStateList.add(newState);
} else {
mAllStates.add(startState);
adjacentStateList = new ArrayList<>();
adjacentStateList.add(newState);
}
mMapForAllStates.put(startStateDesc, adjacentStateList);
// update mapping in startState
for (IState state : mAllStates) {
boolean isStartState = state.getStateDesc().equals(startState.getStateDesc());
if (isStartState) {
startState.addTransit(action, newState);
}
}
}
#Override
public void removeState(String targetStateDesc) {
// validate state
if (!mMapForAllStates.containsKey(targetStateDesc)) {
throw new RuntimeException("Don't have state: " + targetStateDesc);
} else {
// remove from mapping
mMapForAllStates.remove(targetStateDesc);
}
// update all state
IState targetState = null;
for (IState state : mAllStates) {
if (state.getStateDesc().equals(targetStateDesc)) {
targetState = state;
} else {
state.removeTransit(targetStateDesc);
}
}
mAllStates.remove(targetState);
}
#Override
public IState getCurrentState() {
return mCurrentState;
}
#Override
public void transit(Action action) {
if (mCurrentState == null) {
throw new RuntimeException("Please setup start state");
}
Map<String, IState> localMapping = mCurrentState.getAdjacentStates();
if (localMapping.containsKey(action.toString())) {
mCurrentState = localMapping.get(action.toString());
} else {
throw new RuntimeException("No action start from current state");
}
}
#Override
public IState getStartState() {
return mStartState;
}
#Override
public IState getEndState() {
return mEndState;
}
}
example:
public class example {
public static void main(String[] args) {
System.out.println("Finite state machine!!!");
IState startState = new StateImpl("start");
IState endState = new StateImpl("end");
IFiniteStateMachine fsm = new FiniteStateMachineImpl();
fsm.setStartState(startState);
fsm.setEndState(endState);
IState middle1 = new StateImpl("middle1");
middle1.addTransit(new Action("path1"), endState);
fsm.addState(startState, middle1, new Action("path1"));
System.out.println(fsm.getCurrentState().getStateDesc());
fsm.transit(new Action(("path1")));
System.out.println(fsm.getCurrentState().getStateDesc());
fsm.addState(middle1, endState, new Action("path1-end"));
fsm.transit(new Action(("path1-end")));
System.out.println(fsm.getCurrentState().getStateDesc());
fsm.addState(endState, middle1, new Action("path1-end"));
}
}
Full example on Github
Well this is an old question but while nobody mentioned here, I will advice to check two existing frameworks before you implement you own State Machines.
One is Spring State Machine most of you are familiar with Spring framework, which allow us to use several features of Spring like dependency injection and everything else that Spring can offer.
It is really great for modelling the lifecycle of an Apparat, with states like INITIALIZING, STARTED, ERROR, RECOVERING, SHUTTINGDOWN, etc.. but I see lots of people are trying to model a Shopping Chart, a Reservation System with it, the memory footprint a Spring State Machine is relatively big to model millions of Shopping Charts or Reservations.
One other disadvantage, Spring State Machine, while has a capability to persist itself for long running processes but it does not have any mechanism to adapt to changes in these processes, if you persist a process and you have to recover it lets say 10 days later with a change occurred in your business process because of new software release / requirement, you have no built in means to deal with it.
I have several blogs, blog1 blog2, demonstrating how you can program Spring State Machine, specially model driven way, if you want to check it.
Mainly because the disadvantages I mentioned, I advice you to look another framework first, Akka FSM (Finite State Machine) which is more fitting with its low memory footprint to have millions and millions of instances and has a capability to adapt changing long running processes.
Now you can develop with Akka framework with Java but believe me because of some missing language elements, you don't want to read the produced code, Scala is a much more fitting language to develop with Akka. Now I hear you saying Scala is too complex, I can't convince my project leads to develop with Scala, to convince you all this is an option, I developed a Proof of Concept application using a Java/Scala hybrid with all Scala Akka Finite State Machine code generated from an UML model, if you want to check it out here the links to the blogs, blog3 blog4.
I hope this information would help you.
Here is a SUPER SIMPLE implementation/example of a FSM using just "if-else"s which avoids all of the above subclassing answers (taken from Using Finite State Machines for Pattern Matching in Java, where he is looking for a string which ends with "#" followed by numbers followed by "#"--see state graph here):
public static void main(String[] args) {
String s = "A1#312#";
String digits = "0123456789";
int state = 0;
for (int ind = 0; ind < s.length(); ind++) {
if (state == 0) {
if (s.charAt(ind) == '#')
state = 1;
} else {
boolean isNumber = digits.indexOf(s.charAt(ind)) != -1;
if (state == 1) {
if (isNumber)
state = 2;
else if (s.charAt(ind) == '#')
state = 1;
else
state = 0;
} else if (state == 2) {
if (s.charAt(ind) == '#') {
state = 3;
} else if (isNumber) {
state = 2;
} else if (s.charAt(ind) == '#')
state = 1;
else
state = 0;
} else if (state == 3) {
if (s.charAt(ind) == '#')
state = 1;
else
state = 0;
}
}
} //end for loop
if (state == 3)
System.out.println("It matches");
else
System.out.println("It does not match");
}
P.S: Does not answer your question directly, but shows you how to implement a FSM very easily in Java.

Categories

Resources