NEW RELEASE NOTE: 1.4.11-RC5 is available.
This guide has been written for release 1.4.11-RC4 and has been updated for 1.4.11-RC5. Main features of release 1.4.11-RC5: Batch animation facilitates the animation of multiple files. The GUI animator is resizable. The animator reports the triggered processing function. Animator reports errors such as “Non-deterministic choice” and “Incomplete specification”. Animator does not clear previous animation steps.
Create a new JSXM project
JSXM projects are Maven projects with a predefined directory structure. The easiest way to create a JSXM project is to use Maven archetypes. You can use either the command line or Eclipse.
Command Line
The following line creates a new JSXM Maven project in the current directory. The project is named Counter. If you want another name for your new project, simply replace the word Counter (in both occurences) with another name.
mvn -DarchetypeGroupId=org.jsxm.archetypes \ -DarchetypeArtifactId=jsxm-quickstart-archetype \ -DarchetypeVersion=1.4 \ -DarchetypeRepository=http://www.jsxm.org/maven2/ \ -DgroupId=org.jsxm.Counter \ -DartifactId=Counter \ -Dversion=1.0 \ -Darchetype.interactive=false \ --batch-mode archetype:generate
You can import the project in Eclipse as a Maven Project: File->Import->Existing Maven Projects->Browse (Navigate to the root folder of the project)->Finish
Eclipse
Follow the guidelines at http://www.jsxm.org/jsxm-maven-plugin/archetypes/eclipse.html
JSXM project Directory structure
The directory structure of a JSXM project (in this case of the Counter project) is as follows:
Counter │ pom.xml │ └───src └───spec └───org └───jsxm └───Counter └───specification │ Counter.xml │ Counter_sets.xml └───testAdapters CounterAdapter.java
-
The Counter.xml file, in the specification folder, is the most important file of the project. It contains the JSXM model which describes the state-based diagram (in XML format) and the transition functions (in XML and Java inline code). This is the file with which you will be working most of the time.
-
The Counter_sets.xml file contains the definition of the state cover and characterization sets. This file is important for the test generation. More information will follow in dedicated sections.
-
The pom.xml files contains all the settings of the project. It has information about the JSXM Maven plugin version used and important parameters for the animation of models and generation of tests. More information will follow in dedicated sections.
-
The CounterAdapter.java file in the testAdapters folder is an empty Java file used for JUnit test generation. More information will follow in dedicated sections.
Configure the new project
As in every Maven project, all settings of a JSXM project are located in the pom.xml file in the folder of the project.
Edit the pom.xml file to change the JSXM version to the current version. Locate the following part:
<plugin> <groupId>org.jsxm.maven.plugin</groupId> <artifactId>jsxm-maven-plugin</artifactId> <version>1.4.11-RC2</version> </plugin>
and change 1.4.11-RC2 to the newest version of JSXM, e.g. 1.4.11-RC5.
Executing basic Maven JSXM goals
Compile the specification
JSXM specifications are XML files with Java inline code. JSXM compilation generates all the necessary files in order to be able to perform animation of models and generation of tests.
Compiling the specification checks for XML validation errors and Java syntax errors. Note that the Counter example is not complete and the validation will fail.
Command Line:
mvn clean jsxm:compile
Eclipse:
Right click on Maven project (e.g. Counter)->Run As->Maven build. Type in Goals: clean jsxm:compile And Run.
Fixing Validation mistakes
The first step in the JSXM compilation phase is the validation of the XML specification file.
The compilation of the new Counter project will have as a result validation errors:
[INFO ] [..] <!-- ########################################################################## → [INFO ] [..] <!-- Validates the specification, sets and definitions--> [INFO ] [..] <!-- ######################################################################### → [ERROR] [..] file:...../Counter/src/spec/org/jsxm/specification/Counter.xml is NOT valid [ERROR] [..] Reason: Duplicate key value [] declared for identity constraint of element "SXM". [ERROR] [..] Validation ended with errors. Resolve errors in order to continue with compilation.
Read carefully the Reason. It might help you identify the mistake. In this case the mistake is that elements within the SXM model do not have unique names. Actually they all have the value “”. Edit the specification in order to fix the errors. In particular, make the following changes in the states, transitions, inputs, outputs, and function sections
<states> <state name="OFF" /> <state name="ON" /> </states> <initialState state="OFF"/> <transitions> <transition from="OFF" function="SwitchOn" to="ON" /> <transition from="ON" function="SwitchOff" to="OFF" /> </transitions> <memory> <declaration /> <initial /> <display /> </memory> <inputs> <input name="on" /> <input name="off" /> </inputs> <outputs> <output name="onOut" /> <output name="offOut" /> </outputs> <functions> <function name="SwitchOn" input="on" output="onOut" xsi:type="OutputFunction" /> <function name="SwitchOff" input="off" output="offOut" xsi:type="OutputFunction" /> </functions>
… delete the sections:
<testinputgeneration> ... </testinputgeneration>
<dependencies> ... </dependencies>
and compile again.
If you made all changes correctly then the compilation will succeed. Congratulations!
[INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building jsxm-quickstart 1.0 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ Counter --- [INFO] Deleting .../Counter/target [INFO] [INFO] >>> jsxm-maven-plugin:1.4.11-RC4:compile (default-cli) @ Counter >>> [INFO] [INFO] --- jsxm-maven-plugin:1.4.11-RC4:validate (validate) @ Counter --- [INFO ] [..] <!-- ########################################################################## --> [INFO ] [..] <!-- Validates the specification, sets and definitions--> [INFO ] [..] <!-- ########################################################################## --> [INFO ] [..] --- Validation completed successfully.! [INFO ] [..] --- Validating phase done : 230 ms [INFO] [INFO] <<< jsxm-maven-plugin:1.4.11-RC4:compile (default-cli) @ Counter <<< [INFO] [INFO] --- jsxm-maven-plugin:1.4.11-RC4:compile (default-cli) @ Counter --- [INFO ] [..] <!-- ########################################################################## --> [INFO ] [..] <!-- Generates the java files from the XML specification --> [INFO ] [..] <!-- ########################################################################## --> [INFO ] [..] Testing directories [INFO ] [..] --- Java files from JSXM specification Counter.xml generated successfully --- [INFO ] [..] --- Compiling phase done : 146 ms [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 3.571s [INFO] Final Memory: 12M/111M [INFO] ------------------------------------------------------------------------
Interactively animate (execute) the specification
The best way to check if your specification is correct is to execute it (or animate it).
Command Line:
mvn clean jsxm:animate-gui
Eclipse:
Right click on Maven project (e.g. Counter)->Run As->Maven build. Type in Goals: clean jsxm:animate-gui And Run.
A Java application, JSXM Animator, opens. (Select Graphs->Graphs View if you are using a release older than 1.4.11-RC5).
Then click Counter, which is the name of the SXM model to animate. On the right side, your will see the inputs for the specific model: on(), off(). Click on on() and the SXM will accept the input, output the value onOut, and move to the state ON. Experiment with other inputs to get acquainted with the animator.
Click File->Save SXM animation to save the animation.
If you are using 1.4.11-RC5 File->Save SXM animation asks you to provide a prefix for your file name. Providing “Counter” will produce a file “Counter_input.xml” in the specification folder. You can then Click on Edit->Reset SXM and start a new scenario and save it with a different prefix to create many scenarios in the specification folder.
Click File->Exit to exit.
The Counter_input.xml animation file is created in the animation folder:
<?xml version="1.0" encoding="UTF-8"?> <sequence xmlns="http://www.jsxm.org/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jsxm.org/schema http://www.jsxm.org/schema/input.xsd"> <call> <input name="on" /> </call> <call> <input name="off" /> </call> ... </sequence>
Batch animate (banimate) the specification
Edit the pom.xml file and add the following configuration (below the version):
<plugin> <groupId>org.jsxm.maven.plugin</groupId> <artifactId>jsxm-maven-plugin</artifactId> <version>1.4.11-RC4</version> <configuration> <banimateAll>true</banimateAll> </configuration> </plugin>
Now execute the goal:
mvn clean jsxm:banimate
A Counter_output.xml file is created in the animation folder. What happened is that the SXM Counter model was fed with all the inputs from the Counter_input.xml file and the inputs together with the outputs where saved into the new file Counter_output.xml.
If you are using 1.4.11-RC5 jsxm:banimate scans the specification folder for all files ending at _input.xml, animates all these files and produces all the corresponding _output.xml files.
<?xml version="1.0" encoding="UTF-8"?> <sequence xmlns="http://www.jsxm.org/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jsxm.org/schema http://www.jsxm.org/schema/output.xsd"> <call> <input name="on" /> <output name="onOut" /> </call> <call> <input name="off" /> <output name="offOut" /> </call> ... </sequence>
IMPORTANT NOTE: If you use a release older than 1.4.11-RC5 and you want to keep different animation files, rename these two files, e.g. to Counter1_input.xml and Counter1_output.xml and repeat the steps of the animation and the b(atch)animation to produce new Counter_input.xml and Counter_output.xml files.
Making the SXM model complete
A model is complete when each one of its inputs is always consumed by a function at any state (and any memory value: More about memory later). Currently there is no function consuming the input off() at state OFF and no function consuming the input on() at state ON. We will treat these cases as loop transitions (not changing the current state) producing an output error (fault).
First we need to add two additional transitions (in the transitions section):
<transition from="ON" function="OnError" to="ON" /> <transition from="OFF" function="OffError" to="OFF" />
We also need to define the output produced in these cases. We can define these as faults (faults work exactly as outputs but represent unexpected situations). We can place the following right after the outputs section.
<faults> <fault name="onError" /> <fault name="offError" /> </faults>
Finally we need to define the functions that label the self-transitions (within the functions section):
<function name="OnError" input="on" fault="onError" xsi:type="FaultFunction" /> <function name="OffError" input="off" fault="offError" xsi:type="FaultFunction" />
Generating Test Cases
The strongest feature of JSXM is its ability to generate tests that can prove that an implementation conforms to the specification. The maven goal for generating test cases is:
mvn clean jsxm:generate
... [INFO ] [...] <!-- ########################################################################## --> [INFO ] [...] <!-- Generates the XML file for tests--> [INFO ] [...] <!-- ########################################################################## --> Exception in thread "pool-4-thread-1" org.jsxm.jsxmcore.runtimeexceptions.StateCoverNotCompleteException: StateCoverNotCompleteException: State cover is not complete! ...
In the current example the goal fails since the sets are not defined properly. Before dealing however with the sets we have to make some necessary additions to the model.
State cover and Characterization sets
The state cover set consists of those sequences of functions that lead the machine to all its states. In the Counter example there are only two states. The initial state OFF is reached by the empty sequence. That’s why the sequence <sequence/> is always part of the state cover set. The state ON is reached by the sequence <sequence><function name="SwitchOn" /></sequence>.
The characterization set allows to uniquely identify the current state of the system by probing the system with inputs and observing the results. For each pair of states we need to identify an input sequence that will have as result different outputs. In the Counter example there is only one pair. The input sequence < on() > at state OFF has as a result the output onOut via the SwitchOn function. The same sequence at state ON has as a result the fault onError via the OnError function. So, in order to distinguish between the two states we need to probe the sequences <sequence><function name="SwitchOn" /></sequence> and <sequence><function name="OnError" /></sequence>
The two sets are declared within the file Counter_sets.xml:
<?xml version="1.0" encoding="UTF-8"?> <sets xmlns="http://www.jsxm.org/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jsxm.org/schema http://www.jsxm.org/schema/sets.xsd"> <!--Characterization definition--> <characterization> <sequence> <function name="OnError" /> </sequence> <sequence> <function name="SwitchOn" /> </sequence> </characterization> <!--StateCover definition--> <statecover> <sequence/> <sequence> <function name="SwitchOn" /> </sequence> </statecover> </sets>
Executing the test generation goal:
mvn clean jsxm:generate
should now succeed and produces two files with test cases:
The file Counter_test.xml in the tests folder within the specification, with XML test cases:
... <sequence name="SwitchOn_SwitchOn"> <call> <function name="SwitchOn" /> <input name="on" /> <output name="onOut" /> </call> <call> <function name="SwitchOn" /> <input name="on" /> <output name="onError" /> </call> </sequence> ...
And the CounterJsxmAdapterTest.java file in the Counter/test/java/jsxm/org/ folder. This is a file consisting of JUnit test cases:
... @Test public void test_k2_3_SwitchOn_SwitchOn() { CounterAdapter obj = new CounterAdapter(); assertEquals("onOut", obj.on()); assertEquals("onError", obj.on()); } ...
Directory structure after test generation
Counter │ pom.xml │ └───src │ └───spec │ │ └───jsxmLogs │ │ └───org │ │ └───jsxm │ │ └───Counter │ │ └───animation │ │ └───specification │ │ │ Counter.xml │ │ │ Counter_sets.xml │ │ └───testAdapters │ │ │ CounterAdapter.java │ │ └───tests │ │ Counter_test.xml │ └───test │ └───java │ └───jsxm │ └───org │ │ CounterJsxmAdapterTest.java │ └───testAdapters │ CounterAdapter.java │ └───target ...
Notice that the JUnit test file is executing tests on a CounterAdapter object, probing two methods on() and off() both returning String results.
So edit the CounterAdapter.java file (the one in the spec folder) so that it looks like this:
package jsxm.testAdapters; import org.jsxm.Counter; public class CounterAdapter { public String on() { return ""; } public String off() { return ""; } }
For the moment both methods return empty strings. We will fix that once we have an implementation to test. Notice also that we import the implementation under test org.jsxm.Counter.
IMPORTANT NOTE: Always edit the test adapter java file in the spec folder and not the one in the test folder. The first file overwrites the second one every time you execute the test generation goal.
Starting an Implementation in Java
Now is the time to write an implementation of our model in Java. According to the model, we need to write a program that can accept two inputs: the on and off commands. Initially only the on command should be accepted. Once the on command is processed only the off should be available. In all other cases an error should be returned.
Start by creating the directory structure for the implementation. Within the src directory create a directory path main/java/org/jsxm/ and inside the directory create the Counter.java file:
package org.jsxm; public class Counter { }
Executing the JUnit Test Cases
To execute the JUnit test cases on the implementation we execute the Maven goal:
mvn clean jsxm:generate test
As expected all test cases will fail since the implementation is empty and the Adapter is not connected to the implementation.
------------------------------------------------------- T E S T S ------------------------------------------------------- Running org.jsxm.CounterJsxmAdapterTest Tests run: 46, Failures: 46, Errors: 0, Skipped: 0, Time elapsed: 0.795 sec <<< FAILURE!
Completing the Implementation in Java
The complete implementation could be:
package org.jsxm; public class Counter { boolean isOn = false; public void setOn() { if (!isOn) isOn = true; else throw new RuntimeException(); } public void setOff() { if (isOn) isOn = false; else throw new RuntimeException(); } }
In that case the adapter should be:
package jsxm.testAdapters; import org.jsxm.Counter; public class CounterAdapter { private Counter counter = new Counter(); public String on() { try { counter.setOn(); } catch (Exception e) { return "onError"; } return "onOut"; } public String off() { try { counter.setOff(); } catch (Exception e) { return "offError"; } return "offOut"; } }
Passing the JUnit Test Cases
Executing the test cases:
mvn clean jsxm:generate test
would now result:
Results : Tests run: 46, Failures: 0, Errors: 0, Skipped: 0 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------
Congratulations, if you made it so far!
In the next section of the guide we will deal with memory, complex inputs and outputs, functions with preconditions and effects and finally test input generators.