We have the first version of the SO module. We can define flows, states and transitions. If this were all we did, it would make it a vanilla (Cake-vanilla, if you’ll pardon the pun) workflow engine.
We have taken an innovative approach to the configuration of the flows. Just like any other workflow engine, we use the concept of FlowDefinitions with many StateDefinitions with many TransitionDefinitions. Using this structure, we can create a directed graph with cycles (flow) with states as its vertices and transitions as its edges. Simple, eh?
You can obviously manually create the definition beans, but you can use annotation-based configuration. Take this code, for example:
@Flow
public class MainFlow {
}
@State(start = true)
public class StartState {
@Transition
@Transactional
public void one() {
}
@Transition(to = “end”)
public void end() {
}
}
@State(end = true)
public class EndState {
@Transition
public void one() {
}
@Transition(to = “start”)
public void restart(@TransitionArgument int i) {
}
}
Without giving a detailed explanation, you can follow the annotation and infer that we have a flow with two states (start and end); each state has two transitions. To use this flow, we can use the FlowSession like so:
// instantiate flow with id “main”
FlowInstance instance = flowSession.instantiate(”main”);
// calls StartState.one() and stays in the start state
instance.performTransition(”one”);
// calls StartState.end() and transitions to end state
instance.performTransition(”end”);
// calls EndState.restart(5) and transitions to start state
instance.performTransition(”restart”, 5);
…
Now, you can ask where we got the names “main”, “one”, “end” and others; I’m sure you can see that the MainFlow class would be the flow with id “main”, but we never said so explicitly in the code. The BeanPostProcessor uses naming strategies that take the ids explicitly set in the annotations or, if the annotation does not have the id set, it takes the class name or the bean name as the identity of the flow, state or transition.
Also, you may notice that the states somehow get attached to the main flow, even though we never defined this. Again, there is a bit of “intelligence” in the module that automatically registers a state with a flow even if no flow id is set if there is only one flow. In more complex applications (ones that use more than one flow), you must explicitly set the flowId value in the @State annotation.
We are going to put much more work into this module, but we can confidently state that the module is an exciting piece of code. The design of the module will allow us to use service orchestration language in the transitions (take a look at the TransitionAction interface and its implementations for a hint of possible solution).