|
@@ -1 +1,140 @@
|
|
-h1. Placeholder
|
|
|
|
|
|
+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!
|
|
|
|
+
|
|
|
|
+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!
|
|
|
|
+
|
|
|
|
+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!
|
|
|
|
+
|
|
|
|
+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!
|
|
|
|
+
|
|
|
|
+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!
|
|
|
|
+
|
|
|
|
+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!
|
|
|
|
+
|
|
|
|
+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!
|
|
|
|
+# 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.
|