Embedding Code in a Model
In what follows, a decision table example is used. There would be no real difference if the model from which code was being generated was a state machine. The programming language used for the examples is Java.
Sometimes you might want to say something like, "If rule One or rule Three applies then call this function, if rule Four applies then execute this piece of code, ..." Of course, it is possible to do this by generating code from the model and adding the necessary code separately. For example, you might have rules like
Using the applyRules() method in the code
generated using the standard Java template,
you could then write code like this:
... Rule rule = Rules.applyRules(Event.$decide, combination, null); if (rule == Rule.decide$A) windsurf() else if (rule == Rule.decide$B) hillwalk() else if ... ...
The disadvantage of this approach is that the model and the
code are disconnected.
For example, if you make a mistake and call
windsurf() instead of hillwalk()
for rule B, the error won't be seen unless you're
inspecting the model at the same time as the code.
Also, whenever you add a new rule or change an existing
rule in the Statestep model, you'll need to change the
code as well.
A better alternative is to specify the outcome within the model (that is, other than as a comment) and then write the code so that it depends only on the outcome, not on the rule. Thus, the rule above might become
and the code you write would change to
... Rules.applyRules(Event.$decide, combination, null); $Activity act = combination.get$Activity(); if (act == $Activity.$windsurf) windsurf() else if (act == $Activity.$hillwalk) hillwalk() else if ... ...
If your model is a finite state machine (rather than a simple decision table as in this case) then you will probably be writing some code like this anyway. However, this approach may sometimes be awkward or insufficient. For example, it may not be possible to create a nice mapping between variable values and the code to be executed — perhaps because suitably descriptive variable value names would become unreasonably long, or maybe there are some rules for which one method should be called and others where you want to invoke four or five different methods.
For such cases, you can add executable code to a rule by embedding it within a comment in the rule's formula field. For example:
Here, we're saying that the method hillwalk()
should be called whenever rule B applies.
Note that special comments containing program code
("hillwalk();") must somehow be
distinguished from ordinary comments ("go hillwalking").
The convention used here is to treat any comment line
starting with "#:" as source code.
Now all that's needed is a way to have this code extracted and copied whenever code is generated from the model. A little extra code added to the code generation template does the trick. For Java code generation, you can add the file RuleCode.java.ftl to the other FTL files in the template package. When you process the template with FMPP, the resulting RuleCode.java will contain code like:
public class RuleCode
{
public static void execute(Rule rule)
{
if (rule == Rule.decide$A)
{
windsurf();
}
else if (rule == Rule.decide$B)
{
hillwalk();
}
...
This is similar to the code we saw first, except that this
time it's been automatically extracted from the model.
In your own code you now need only call the
execute() method:
... Rule rule = Rules.applyRules(Event.$decide, combination, null); RuleCode.execute(rule); ...
This approach works well for code generation but it does mean "contaminating" the Statestep model with the source code of a particular programming language, that is, with low level implementation details. If your model is also to serve as a specification, you might want to consider using a script to strip out any embedded source code before passing a HTML version of the model to reviewers.
Variations
Variations on this idea are possible. For example, the embedded code might be identified in a different way (or perhaps all comments can be assumed to be code) or the template might be changed to take the contents of any comments in a rule formula and echo them as strings to the output.
Another possibility is to implement Rules.ExtraLogic
and so allow code embedded in a rule to change the values
of variables in the next state or to veto the rule.
You can do this by taking the
same template code
and simply changing the lines:
public class RuleCode
{
private RuleCode() { }
public static void execute(Rule rule)
{
<@code_for_rules/>
}
to
public class RuleCode implements Rules.ExtraLogic
{
public boolean confirmRule(Rule rule,
Combination current, Combination next)
{
<@code_for_rules/>
return true;
}
In your own Java code, you would then pass an instance of
this class to Rules.applyRules(), for example:
... Rules.ExtraLogic logic = new RuleCode(); Rules.applyRules(Event.$decide, comb, logic); ...
You might then have rules with code like this:
or with code which can veto the rule - that is, which helps to determine whether or not the rule applies:
Note that Statestep reports a conflict between these two rules. That's because Statestep ignores comments and so the two rules appear to specify different outcomes in the same cases. The preceding rule, which is equivalent to the two rules above, avoids this problem.
Questions, comments? info2@statestep.com