123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- h1. Generating Java source code
- YAKINDU Statechart Tools include code generators for Java, C, and C++ out of the box. The code generators are following a "code-only" approach: They are generating all the code that is needed and do not rely on any additional runtime libraries. The generated code provides a well-defined application programming interface and can be integrated easily with any client code. In this tutorial we will generate Java code representing our *CallHandling* example.
- h2. Creating a generator model
- For code generation, SCT uses a textual generator model called *SGen*. The generator model holds key parameters for the code generation process and allows for the latter's customization.
- The first step to code generation is to create a new SGen model. Right-click on the _model_ folder in the project explorer and select _New → Code Generator Model_ from the context menu.
- !images/callhandling_200_generation_create_generator_model.png(Selecting "New → Code Generator Model" in the context menu)!
- The _YAKINDU Generator Model_ wizard opens. Change the _File name_ to *CallHandling.sgen*, then click _Next >_.
- !images/callhandling_210_generation_new_sgen_model_1.png(Selecting a filename for the generator model)!
- From the _Generator_ drop-down menu at the top, select _Yakindu SCT Java Code Generator_.
- In the statechart tree beneath that menu, check the *CallHandling.sct* model, then click _Finish_.
- !images/callhandling_220_generation_new_sgen_model_2.png(Selecting generator type and statechart model)!
- Now the wizard creates the default SGen model for Java code generation and opens it in an SGen editor. The project explorer on the left-hand side shows the new model file _CallHandling.sgen_.
- !images/callhandling_230_generation_new_sgen_model_3.png(The generator model)!
- Here's the generator model once again as plain text:
- bc(prettyprint)..
- GeneratorModel for yakindu::java {
- statechart CallHandling {
- feature Outlet {
- targetProject = "CallHandling"
- targetFolder = "src-gen"
- }
- }
- }
- p. Let's have a closer look at the listing above:
- * @yakindu::java@ is the unique ID of the Java code generator.
- * The @statechart CallHandling { … }@ block references the statechart model we want to generate code for.
- * The @feature Outlet { … }@ block specifies where the generated code artifacts are to be placed, i. e. in the Eclipse project @CallHandling@ and within that project in the @src-gen@ folder.
- A statechart reference may contain various configuration features. You will learn more about feature later.
- h2. Enhancing the generator model by timing capabilities
- However, the default generator model is insufficient yet. The _CallHandling_ statechart model uses _after_ and _every_ expressions. That is, it is dealing with *timed events*, requiring a timer service to trigger them. We can instruct the code generator to provide us with a default timer service implementation by adding the following feature to the generator model:
- bc(prettyprint).
- feature GeneralFeatures {
- TimerService = true
- }
- h2. Generating Java source code
- What do we have to do to actually start the Java source code generation? Nothing!
- The generator model is executed by a so-called Eclipse *builder*. That is, as long as the _Project → Build Automatically_ menu item is checked (which it is by default), the artifacts are generated automatically with each modification of the statechart model or of the generator model.
- As you can see in the project explorer, the folder _src-gen_ has been created and populated with the generated Java source code artifacts.
- !images/callhandling_240_generation_timer_service.png(Adding the timer service feature)!
- Add the generated artifacts to the Java build path by right-clicking on the _src-gen_ folder and selecting _Build Path → Use as source folder_ in the context menu.
- !images/callhandling_250_generation_use_as_source_folder.png(Declaring "src-gen" as a source folder)!
- If you want to execute your generator model manually, select _Generate Statechart Artifacts_ from the @.sgen@ file's context menu in the project explorer.
- h2. Integration with client code
- Now that we have a generated Java implementation of the _CallHandling_ state machine available, we want to actually use it from some client code. We'll create that client code in a second.
- h3. Creating client code
- Let's establish a new Java class _CallHandlingClient_ and integrate the state machine with it:
- # Right-clicking on the _src_ folder.
- # Select _New → Class_ in the context menu.
- # Name it _CallHandlingClient_.<br/>!images/callhandling_300_java_integration_create_new_class.png(Creating some Java client source code)!
- # Click _Finish_.
- Next, copy the following code into the created class (without the line numbers, of course):
- bc(prettyprint linenums)..
- 1 import org.yakindu.scr.TimerService;
- 2 import org.yakindu.scr.callhandling.CallHandlingStatemachine;
- 3
- 4 public class CallHandlingClient {
- 5
- 6 public static void main(String[] args) throws InterruptedException {
- 7
- 8 // Create the state machine:
- 9 CallHandlingStatemachine sm = new CallHandlingStatemachine();
- 10 sm.setTimer(new TimerService());
- 11
- 12 // Enter the state machine and implicitly activate its "Idle" state:
- 13 sm.enter();
- 14
- 15 // Raise an incoming call:
- 16 sm.getSCIPhone().raiseIncoming_call();
- 17 sm.runCycle();
- 18
- 19 // Accept the call:
- 20 sm.getSCIUser().raiseAccept_call();
- 21 sm.runCycle();
- 22
- 23 // Keep the phone conversation busy for a while:
- 24 for (int i = 0; i < 50; i++) {
- 25 Thread.sleep(200);
- 26 sm.runCycle();
- 27 }
- 28
- 29 // Before hang-up, output the duration of the call:
- 30 System.out.println(String.format("The phone call took %d seconds.",
- 31 sm.getSCIPhone().getDuration()));
- 32
- 33 // Hang up the phone:
- 34 sm.getSCIUser().raiseDismiss_call();
- 35 sm.runCycle();
- 36 }
- 37 }
- p. Let's have a detailed look at this client code:
- * First, this program creates a new instance of the state machine by calling the default constructor of @CallHandlingStatemachine@ (line 9).
- * Since we are using timed events, the statechart implementation requires an implementation of the @ITimer@ interface. Since we added the @TimerService@ feature to the generator model, the code generator creates a default implementation @org.yakindu.scr.TimerService@ that uses the @java.util.Timer@ class. A new instance of the default @TimerService@ is created and set to the state machine (line 10).
- * In line 13, @sm.enter()@ enters the state machine and – via its initial state – activates its *Idle* state.
- * For each interface in the statechart definition block a getter method has been generated, here @getSCIPhone()@ and @getSCIUser()@. You can access all incoming events and all variables via these interfaces. In line 16, the _incoming_call_ event is raised, activating the *Incoming Call* state after the next run cycle has been executed (line 17).
- * In line 20, we raise the _accept_call_ event via the _User_ interface. It activates the *Active Call* state after the next run cycle has been performed (line 21).
- * From line 24 to line 27, the run cycle is executed periodically every 200 milliseconds.
- * After that, the call's duration is printed to the console (lines 30 and 31).
- * Finally, the _dismiss_call_ event is raised (line 34), activating the *Dismiss Call* state after the next run cycle (line 35).
- h3. Executing the client code
- You can execute the client code via _Run As → Java Application_ from the class file's context menu.
|