This example explains how to develop a custom code generator for the open source framework YAKINDU Statechart Tools. In this example, we will generate Statechart XML (SCXML) from a simple stopwatch state machine. The stopwatch use case is taken from the Apache Commons SCXML site. The stopwatch model consists of four different states (ready, running, stopped, and paused) and the state transitions are triggered by events that represent the stopwatch buttons (watch.start, watch.stop, watch.split, watch.unsplit, watch.reset).
Note that this example is not a full-fletched Statechart XML code generator, only the basic concepts of states, transitions and events are supported to showcase how to get started. We expect the following XML fragment to be generated from the model above:
<?xml version="1.0" encoding="UTF-8"?> <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="ready"> <state id="ready"> <transition event="watch.start" target="running" /> </state> <state id="running"> <transition event="watch.split" target="paused" /> <transition event="watch.stop" target="stopped" /> </state> <state id="paused"> <transition event="watch.stop" target="stopped" /> <transition event="watch.unsplit" target="running" /> </state> <state id="stopped"> <transition event="watch.reset" target="ready" /> </state> </scxml>
Before starting with a code generator, we have to decide which of the two available meta models is most suitable for the use case. In model driven software development, a model always conforms to another model commonly referred to as a meta model. This meta model defines the building blocks a model can consist of. When developing a generator for YAKINDU SCT you can choose between two different meta models, Sgraph and SExec. In broad terms, SGraph represents the structure of the modeled statemachine (States, Transitions, Events) while SExec contains sequences that encapsulates our execution semantics (for example Checks, Calls and Stateswitch).
The SGraph meta model is similar to the state machine meta model known from the UML. We have a top level element Statechart that contains a set of States and Transitions. Transitions may have events and a source and a target State. The following shows a very simplified version of SGraph.
In contrast, the SExec meta model defines an ExecutionFlow that contains a set of ExecutionStates. Every ExecutionState has an entry and an exit sequence of different Steps. Each Step can be of a different type, for example a StateSwitch or a Check.
If you want to generate code for a runtime environment that somehow interprets a statechart structure (for example SCXML or Spring Statemachine) you should pick SGraph meta model. If you want to generate a code-only approach for another programming language and you want to ensure that it behaves exactly in the way all the other code generators behave you should pick the SExec meta model.
Creating custom code generators is really easy, it is a first-level concept in YAKINDU Statechart Tools. You can develop them directly within your project workspace. This is pretty awesome - adoptions to the model or the generator templates are executed instantly and you don't have to bother with long code-compile-test cycles. More information about how to setup a new code generator project is out of the scope of this blog post and can be found here.
When choosing the language for developing a new generator, you should consider using Xtend instead of Java. The syntax is familiar for every Java developer, but it adds some nice features like template expressions and dispatch methods that are really useful for developing code generators.
The example Statechart XML generator implemented with Xtend could look like this:
The SCXMLGenerator class implements the ISGraphGenerator interface. This interface defines which meta model will be used for the code generator. If you want to implement a code generator based on the ExecutionFlow meta model you would implement IExecutionFlowGenerator interface instead.
The generate function uses Xtends template string to generate the scxml header. Most of the text ist static except the value for the initial attribute – this is calculated in the initialState function. After the scxml header, the generate function for the head region (parallel regions are not implemented) is called. This function simply iterates over all states in this region and calls the generate function for states . Other vertex types, for example Histories, Synchronizations or Final States are filtered out. Last, the generate function for states creates a new XML element and iterates over all outgoing transitions to generate the nested transition element.
You can download the complete generator project form our new examples repository. If you want to run the generated SCXML you could for example use the apache commons-scxml interpreter.