Code Snippet

Table of Contents

logo-large

Tutorial Actifsource Tutorial – Code Snippet
Required Time - 120 Minutes
Prerequisites - Actifsource Tutorial – Installing Actifsource
- Actifsource Tutorial – Simple Service
- Actifsource Tutorial – State Machine
Goal - Add conditional expression to a transition
- Add code as an action to a transition which will be executed together with the transition
Topics covered - Code Snippet Editor
- Code templates to generate code from code snippets
Notation ↪ To do
ⓘ Information
Bold: Terms from actifsource or other technologies and tools
Bold underlined: actifsource Resources
Monospaced: User input
Italics: Important terms in current situation
Disclaimer The authors do not accept any liability arising out of the application or use of any information or equipment described herein. The information contained within this document is by its very nature incomplete. Therefore the authors accept no responsibility for the precise accuracy of the documentation contained herein. It should be used rather as a guide and starting point.
Contact Actifsource AG
Täfernstrasse 37
5405 Baden-Dättwil
Switzerland
www.actifsource.com
Trademark Actifsource is a registered trademark of Actifsource AG in Switzerland, the EU, USA, and China. other names appearing on the site may be trademarks of their respective owners.

Overview

  • Create a meta-model for Statemachine instantiate Statemachine and write a code template to generate a simple implementation of your Statemachines in C++ as seen in the Actifsource Tutorial State Machine

image2 image2

  • Add a Code Snippets with conditional expressions to Transition
  • Create a Domain Diagram for an instance of Statemachine and show the conditions for Transitions in the diagram
  • Generate code for Statemachines that checks the associated condition before executing a transition
  • Add a Code Snippet with an action to Transition and generate code that executes the action together with the state transition

Part I Preparation

image3 image3

Setup a project ch.actifsource.tutorial.statemachine.code with a meta-model for Statemachine create two instances of Statemachine and implement a code template for Statemachine as seen in the Actifsource Tutorial State Machine:

  • Prepare a new Actifsource Project ch.actifsource.tutorial.statemachine.code
  • Create a meta-model for Statemachine
  • Create two instances of type Statemachine namely Statemachine1 and Statemachine2
  • Write a code template StatemachineImpl for the type Statemachine
  • Use the package structure shown above

Part II Implement conditional transitions

image4 image4

First, we import all the resources needed to enable the support of Code Snippets in our project:

  • Select the project ch.actifsource.tutorial.statemachine.code and choose Project->Properties from the main menu
  • In the properties dialog choose Actifsource and go the Built-in Dependencies tab
  • Click on Add Builtin
  • In the dialog Select a built-in dependency choose CODESNIPPET and click on OK

image5 image5

  • Close the Properties dialog by clicking on OK

image6 image6

We add a Code Snippet relation to class Transition:

  • Open the class Transition in the Resource Editor
  • Add a (third) property to the class
  • Choose StructuredCodeSnippetRelation in the dialog Type Selection

image7 image7

  • Insert condition as name of the relation
  • Create a new CodeSnippetRelationAspect as shown above
  • Choose Cardinality0_1 as subjectCardinality and as objectCardinality
  • Create a new language statement by calling the Content Assist and choosing CMinusCondition

image8 image8

We add a new Composition called variable to the class Statemachine:

  • Open Transition in the ResourceEditor
  • Add a new property and choose Composition in the Type Selection dialog
  • Insert variable as the name of the relation
  • Choose new ch.actifsource.core.Class as the range with the support of the Content Assist

image9 image9

  • Insert Variable as name of the newly created class, which is opened automatically in the Resource Editor

image10 image10

A conditional expression for a Transition should be able to use all Variables that are owned by the Statemachine of the Transition as variables:

  • Insert a RelationTokenProvider
  • Define the Selector Transition.-transition.-state.counter which selects all Variables that are owned by the Statemachine of the Transition
  • Choose ch.actifsource.codesnippet.metamodel.TokenType.Variable as tokenType

image11 image11

We add a condition to the state transition triggered by the event start that restricts the number of times the Statemachine can switch to the State Started

  • Open the instance Statemachine1 in the ResourceEditor
  • Add two statements for variable to Statemachine1
  • Choose startCounter as the name of the first and startLimit as the name of the second Variable

image12 image12

image13 image13

We add a conditional expression to the state transition triggered by the Event start in the State Initialized

  • Open the state Initialized in the Resource Editor and then open its Transition start
  • Open the Code Snippet Editor by selecting the relation condition and pressing Enter
  • Call the Content Assist in the Code Snippet Editor and choose startCounter
  • Enter ' < ' in the Code Snippet Editor and call the Content Assist again
  • Choose startLimit in the Content Assist

image14 image14

We enforce that the Statemachine can only switch a maximum of startLimit times to the State Started by adding the same conditional expression also to the Transition triggered by the Event start in the State Stopped

  • Enter the conditional expression in the same way as on the previous page

Part III Create a Domain Diagram

image15 image15

We create a new Diagram Type called Statemachine in order to define properties of Domain Diagrams of Statemachines:

  • Select the package ch.actifsource.tutorial.statemachine.code.generic and choose New -> Diagram Type

image16 image16

  • Enter Statemachine as name for the newly created DiagramType in the New DiagramType Wizard
  • Choose ch.actifsource.tutorial.statemachine.code.generic.Statemachine as RootClass

image17 image17

  • Define allowedClass as ch.actifsource.tutorial.statemachine.code.generic.State
  • Choose ShowPaletteEntry as paletteEntry
  • Insert an allowedRelation of type AllowedIndirectRelation with selector State.transition.targetState

image18 image18

Now we create a new Domain Diagram for Statemachine1 based on the newly created Diagram Type:

  • Select ch.actifsource.tutorial.statemachine.code.specific and choose New -> Domain Diagram

image19 image19

  • Check the chosen settings in the open dialog and click Finish

image20 image20

image21 image21

  • Choose Select in the Palette of the Diagram Editor and arrange the States such that all transitions are visible

image22 image22

Next, we will see how to display the conditional expressions associated with a Transition in the Domain Diagram. First, we create a function that generates the displayed text from the conditional expression:

  • Select the package ch.actifsource.tutorial.statemachine.code.generic and choose New -> FunctionSpace

image23 image23

  • Enter NameFunctions as name of the FunctionSpace

image24 image24

  • Create a new FunctionContext with typeRef ch.actifsource.tutorial.statemachine.code.generic.Transition
  • Create a new function in the FunctionContext and choose TemplateFunction in the Type Selection dialog

image25 image25

  • Enter displayName as name of the TemplateFunction
  • Open the TemplateFunction in the Template Function Editor by double-clicking on displayName in the Project Explorer

image26 image26

The function should display the name of the event triggering the Transition and in brackets the conditional expression if there is one:

  • Enter Transition.event.name in the TemplateEditor followed by '[]'
  • Place the cursor inside the brackets and choose Insert ColumnContext from the menu

image27 image27

  • Choose Transition.condition as selector for the column context
  • Enter CodeSnippet.displayCodeSnippetSingleLine@DisplayCodeSnippet in the column context. This function outputs a string that represents the expression in the Code Snippet as entered by the user, i.e., without parsing or processing it

image28 image28

We will use the newly created function displayName to define a NameAspect for Transitions

  • Create a NameAspect with the Content Assist and choose TextSelectorAspectImplementation in the Select Decoration Type dialog

image29 image29

  • Enter Transition.displayName@NameFunction as selector of the NameAspect, i.e., the name of the Transition will be the output of the function we have defined before

image30 image30

  • Open the Statemachine1 Domain Diagram again and check that the Transitions are now displayed with their name including the conditional expressions as specified above

Part IV Generate code for conditional transitions

image31 image31

In this part, we will extend the template StatemachineImpl as implemented in the Actifsource Tutorial State Machine such that the statemachine executes a state transition only if the associated condition is fulfilled:

  • Open the template StatemachineImpl in the Template Editor

image32 image32

We write an if-statement with the conditional expression associated with a Transition as condition:

  • Insert a new Line Context and write the selector Transition.condition for the newly created context

image33 image33

  • Write an if-statement in the new line context and insert a call to the function toC@CodeSnippetToCode on the CodeSnippet available in the this context as condition of the if-statement
  • Add opening and closing braces around the existing assignment expression

image35 image35

  • Open the generated files Statemachine1Impl.hpp (overwritten) and Statemachine2Impl.hpp (unchanged) and inspect the changes.

Part V Customized variable names

image36 image36

  • The built-in template functions that we used so far generate the name of variables (and also functions) by calling simple name on the corresponding resource
  • In this part we will change the generated variable names by adding a prefix to the variable names according to our naming convention

image37 image37

  • Create a new Java source folder: select the project ch.actifsource.tutorial.statemachine.code and choose New -> Source Folder from the menu

image38 image38

  • Insert aspects as name of the new folder

image39 image39

image40 image40

  • Create a new package ch.actifsource.tutorial.statemachine.code.generic in the aspects folder: select the aspects folder and choose New -> Package from the menu

image41 image41

  • Select the package ch.actifsource.tutorial.statemachine.code.generic in the folder aspects and choose New -> Interface from the menu
  • Write IMyNameProvider as name of the new interface
  • Choose ch.actifsource.codesnippet.metamodel.template.INameProvider as Extended interface

image42 image42

  • Select the package ch.actifsource.tutorial.statemachine.code.generic in the folder aspects and choose New -> Class from the menu
  • Write MyNameProviderLiteralAspect as name of the new class
  • Choose ch.actifsource.core.model.aspects.impl.AbstractStatelessAspectImpl as Superclass
  • Choose ch.actifsource.core.model.aspects.impl.IGenericLiteralAspect<IMyNameProvider> as Interface
  • Click Finish
package ch.actifsource.tutorial.statemachine.code.generic;

import javax.annotation.CheckForNull;

import ch.actifsource.core.INode;
import ch.actifsource.core.Literal;
import ch.actifsource.core.job.IReadJobExecutor;
import ch.actifsource.core.model.aspects.impl.AbstractStatelessAspectImpl;
import ch.actifsource.core.model.aspects.impl.IGenericLiteralAspect;
import ch.actifsource.core.scope.IResourceScope;

public class MyNameProviderLiteralAspect extends AbstractStatelessAspectImpl implements IGenericLiteralAspect<IMyNameProvider> {

  @Override
  public boolean allowMultiline() {
    return false;
  }

  @Override
  public @CheckForNull String isValid(IReadJobExecutor executor, IResourceScope scope,
    String value) {
    return null;
  }

  @Override
  public Literal create(IMyNameProvider value) {
    return new Literal(value.toString());
  }

  @Override
  public @CheckForNull String getJavaConstructionExpression(IReadJobExecutor executor,
    IResourceScope scope, INode node) {
    return null;
  }

  @Override
  public @CheckForNull IMyNameProvider getValue(IReadJobExecutor executor,
    IResourceScope scope, INode node) {
    return null;
  }

  @Override
  public Class<IMyNameProvider> getValueType() {
    return IMyNameProvider.class;
  }

}
  • In the newly created class remove all TODO comments
  • Write the statement return MyNameProvider.class; in the method getValueType()
  • Write the statement return new Literal(value.toString());

image44 image44

  • Create a new Literal type: select the package ch.actifsource.tutorial.statemachine.code.generic in the folder asrc and choose New -> Resource from the menu
  • Choose the type ch.actifsource.core.Literal as Type of the new Resource
  • Write MyNameProviderLiteral as Name of the new Resource

image45 image45

  • Open the new Literal in the Resource Editor
  • Create a LiteralAspect with type JavaAspectImplementation and choose the class ch.actifsource.tutorial.statemachine.code.generic.MyNameProviderLiteralAspect as className
  • Let the MyNameProviderLiteral extend ch.actifsource.codesnippet.metamodel.parsetree.template.NameProvider, which is the default NameProvider and generates names by calling simpleName@BuiltIn

image46 image46

  • Create a new FunctionSpace Select the package ch.actifsource.tutorial.statemachine.code.generic in the asrc folder and choose New -> FunctionSpace
  • Insert TokenNameFunctions as the name of the FunctionSpace and click Finish

image47 image47

  • Let the new FunctionSpace TokenNameFunctions extend from TokenToName

image48 image48

  • Open the FunctionSpace TokenNameFunctions in the Resource Editor
  • Create a new FunctionContext with typeRef MyNameProviderLiteral
  • Create a new function and choose TemplateLineFunction from the Type Selection dialog

image49 image49

  • Insert variableName as the name of the new TemplateLineFunction
  • Create a parameter Param of type ClassType and with classRef ch.actifsource.core.Resource
  • Insert m_Resource.simpleName@BuiltIn as text, i.e., the function appends the prefix m_ to the output of Resource.simpleName@Builtin
  • Warning: Please choose the exact function name for variableName or functionName since these functions are overwritten

image50 image50

  • Create a new FunctionContext with typeRef Statemachine
  • Create a new function and choose JavaFunction from the Type Selection dialog

image51 image51

  • Insert generateNameProvider as name of the function
  • Create a statement returnType of type LiteralType with literalRef MyNameProviderLiteral

image52 image52

    @Override
    public ch.actifsource.tutorial.statemachine.code.generic.IMyNameProvider generateNameProvider(final ch.actifsource.tutorial.statemachine.code.generic.javamodel.IStatemachine statemachine) {
      /* Begin Protected Region [[835774eb-ee6c-11ef-8f29-099ac721970d]] */
      return new IMyNameProvider() {};
      /* End Protected Region   [[835774eb-ee6c-11ef-8f29-099ac721970d]] */
    }
  • Save the FunctionSpace TokenNameFunctions
  • Open the newly generated file TokenNameFunctions.java in the Java Editor
  • Write the statement return new IMyNameProvider(){} inside the protected region in the method body of the method generateNameProvider
  • Save the file

image54 image54

  • Open the template StatemachineImpl in the Template Editor
  • Insert a new LineContext on the line after the case expressions
  • Choose Transition.condition as the selector of the new context

image55 image55

  • Insert a new LineContext on the same line
  • Choose Statemachine.generateNameProvider@TokenNameFunctions:NameProvider as selector of the new context
  • Write an if-statement with CodeSnippet.toCwithNameProvider@CodeSnippetToCode
Info

Note that there is an error on the edited line because the parameter to the function cannot be resolved

image56 image56

  • Insert a new line context on the same line and choose CodeSnippet:CodeSnippet (This dummy context allows Actifsource to correctly and automatically resolve the parameter to the function from the contexts)

  • Save the template and make sure that the code is generated

image58 image58

  • Open the file Statemachine1Impl.hpp and check that the variable names have been generated with the defined prefix "m_"

Part VI Implement actions for transitions

image59 image59

In this part, we will see how to add an action to a transition. We add the code corresponding to the action as a Code Snippet to the model. This code will be executed together with the transition:

  • Open the class Transition in the Resource Editor and add a Code Snippet relation as already seen in Part II
  • Insert action as name of the StructuredCodesnippetRelation choose subjectCardinality and objectCardinality Cardinality0_1
  • Create a RelationTokenProvider with selector Transition.-transition.-state.variable and tokenType Variable
  • Choose the language CMinus

image60 image60

We will now increment the startCounter each time that we switch to the State Started:

  • Open Statemachine1 in the Resource Editor
  • Add an action to the State Initialized and insert the code startCounter = startCounter + 1; into the Code Snippet Editor
  • Add an action to the State Stopped and insert the code startCounter = startCounter + 1; into the Code Snippet Editor

image61 image61

  • Open the template StatemachineImpl in the Template Editor
  • Add a new line context after the assignment statement that updates the state
  • Choose Transition.action as the selector of the state (to insert code for Transitions which have an action defined)
  • Call the function toCwithNameProvider@CodeSnippetToCode on the CodeSnippet in the new line context
Info

Note that there is an inconsistency because we have not yet added a NameProvider to our contexts which can be used as the parameter to the function

image62 image62

  • Add a new line context on the same line as before and choose Statemachine.generateNameProvider@TokenNameFunctions:NameProvider as selector of the context
  • Add another line context on the same line and choose the selector CodeSnippet:CodeSnippet (needed for the parameter matching)
  • Save the template and make sure that the code in Statemachine1Impl.hpp is generated and overwritten

image64 image64

  • Open the file Statemachine1Impl.hpp and check that the code that increments the counter has been correctly inserted
  • Complete the generated classes by adding a member function initialize() and the missing variables (and probably adding the cases for the missing enumeration values to make the compiler happy).

actifsource-point-large