Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/* Copyright or (C) or Copr. GET / ENST, Telecom-Paris, Ludovic Apvrille
*
* ludovic.apvrille AT enst.fr
*
* This software is a computer program whose purpose is to allow the
* edition of TURTLE analysis, design and deployment diagrams, to
* allow the generation of RT-LOTOS or Java code from this diagram,
* and at last to allow the analysis of formal validation traces
* obtained from external tools, e.g. RTL from LAAS-CNRS and CADP
* from INRIA Rhone-Alpes.
*
* This software is governed by the CeCILL license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL license and that you accept its terms.
*/
package avatartranslator.tosysmlv2;
import avatartranslator.*;
import static avatartranslator.AvatarTransition.*;
import static avatartranslator.tosysmlv2.Avatar2SysMLNames.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.function.BiConsumer;
/**
* Class Avatar2SysMLV2
* Creation: 20/06/2024
*
* @author Sophie Coudert
* @version 0.1 20/06/2024
*/
/** the source Avatar Specification */
private AvatarSpecification avspec;
/** the buffer in which theSysML Model is written (returned at the end of the generation process) */
private StringBuffer avsysml;
/** signals concerned by AvatarQueryOnSignal (collected at beginning because require some specific handling)*/
private HashSet<AvatarSignal> fifoSet = new HashSet<AvatarSignal>();
/** infos about methods and signals collected while generation declarations and used while generating state machines */
private HashMap<AvatarMethod, MethodInfo> methodMap = new HashMap<AvatarMethod, MethodInfo>();
/** path from top level to the block (block sequence) being currently handled */
private ArrayList<String> blockChain = new ArrayList<String>();
/** SysML code to make inner blocks visible at top level. Contains one declaration per inner block */
private StringBuffer blockLinks;
/** the standard indentation step string */
private final String indentStep = " ";
/** size of the standard indentation step */
private final int indentStepSize = 4;
/** the current indentation string */
private String indentation;
/** (fixed) header for any Avatar SysML model instance */
private final String header = "package AvatarInstance {\n" +
Sophie Coudert
committed
indentStep + "private import AvatarGeneral::*;\n" +
indentStep + "private import AvatarBlockTypes::*;\n" +
indentStep + "private import AvatarCommunication::*;\n" +
indentStep + "private import AvatarTransitionServer::*;\n";
public Avatar2SysML(AvatarSpecification _avspec) { avspec = _avspec; }
/** the generator. Builds the SysML model of the specification provided to the constructor */
public StringBuffer avatar2SysML() {
fifoSet.clear();
methodMap.clear();
blockChain.clear();
indentation = "";
blockLinks = new StringBuffer(indentStep + "// Block Shortcut Links $$$$$$$$$$$$\n");
avsysml = new StringBuffer(header);
indent(1);
searchCountSignals();;
dataTypes2SysML();
communications2SysML();
blocks2SysML();
avsysml.append(blockLinks);
avsysml.append("}\n");
return avsysml;
}
/** increase indentation */
private void indent(int n) { for (int i= 0; i < n; i++) indentation += indentStep; }
/** decrease indentation */
private void unindent(int n) { indentation = indentation.substring(n * indentStepSize); }
/** infos collected while generating declarations of methods and signals, to be used later.
*
* Used when generating state machine description, for example when handling ActionsOnSignal. */
static private class MethodInfo {
private String name; // method name
private String msgtype; // null for methods that are not signals
private ArrayList<String> fieldNames; // names of parameters
private ArrayList<AvatarType> fieldTypes; // int, bool or undefined
private ArrayList<AvatarDataType> dataTypes; // datatype for "undefined" fieldType, otherwise null.
private AvatarType returnType; // int, bool or undefined
private AvatarDataType returnDataType; // datatype if returnType is "undefined", otherwise null.
/** for void methods (without return type) */
MethodInfo(String _name) {
name = _name;
msgtype = null;
fieldNames = new ArrayList<String>();
/** for non-void methods (with return type) */
MethodInfo(String _name, AvatarType _returnType, AvatarDataType dt) {
name = _name;
msgtype = null;
fieldNames = new ArrayList<String>();
returnDataType = null;
else
returnDataType = dt;
/** for signals */
MethodInfo(String _name, String _msgtype) {
name = _name;
msgtype = _msgtype;
fieldNames = new ArrayList<String>();
* @param _dt datatype, only relevant if _type is UNDEFINED
*/
public void addField(String _fieldName, AvatarType _type, AvatarDataType _dt){
else if (!(_type == AvatarType.BOOLEAN || _type == AvatarType.INTEGER))
return; // unknown type... TO CHANGE ? ...
fieldNames.add(_fieldName);
fieldTypes.add(_type);
public int getArity() { return fieldNames.size(); }
/** SysML name */
public String getName(){ return name; }
/** SysML name for message type describing profile */
public String getMessageType(){ return msgtype; }
/** method Avatar return type (null if none)*/
public AvatarType getReturnType(){ return returnType; }
/** method Avatar return datatype (null if no return type or return primitive type)*/
public AvatarDataType getReturnDataType(){ return returnDataType; }
public String getFieldName(int i){ return fieldNames.get(i); }
/** ith parameter Avatar type */
public AvatarType getFieldType(int i){ return fieldTypes.get(i); }
/** ith parameter Avatar datatype (null if primitive type)*/
public AvatarDataType getDataType(int i){ return dataTypes.get(i); }
* Memorized while naming states, to be reused for generating states
*/
static private class StateInfo {
/** SysML name */
private String name;
/** Sysml name of the state that is technically added before this (if exists) */
private String prename = "";
/** for states that havn't technically added state before them
* @param _name SysML name
*/
/** for states that have a technically added state before them
* @param _name SysML name of the state
* @param _prename SysML name of the technically added state before
*/
StateInfo(String _name, String _prename) { name = _name; prename = _prename; }
/** SysML name of the technically added state before */
public String getPreName(){ return prename; }
}
/** Collect (in fifoSet) all signals that are used in an AvatarQueryOnSignal element of the specification.
*
* (they require some specific handling while generating...)
*/
private void searchCountSignals() {
for(AvatarBlock block: avspec.getListOfBlocks()) {
for(AvatarStateMachineElement sme : block.getStateMachine().getListOfElements()) {
if(sme instanceof AvatarQueryOnSignal)
fifoSet.add(((AvatarQueryOnSignal) sme).getSignal());
}
}
}
/** update path blockChain when entering the block-handling procedure for a a block / sub-block
* @param _block: the block /sub-block to handle
*/
private void chainBlock(String _block) { blockChain.add(_block); }
/** update path blockChain when exiting the block-handling procedure for a a block / sub-block */
private void unchainBlock() { if(blockChain.size() > 0) blockChain.remove(blockChain.size() - 1); }
/** generate SysML code to make a block visible at top level through its name (and not its path).
*
* Links block name to block path (updates blockLinks which is added to avsysml at the end of
* the generation process). Consistent because all blocks have different names.
*/
private void blocklink() {
for (int i=0; i < size-1; i++){
chain.append(blockChain.get(i) + ".");
}
chain.append(blockChain.get(size - 1));
blockLinks.append( indentStep + "part " + blockChain.get(size - 1) +
" : '#AvatarBlock' :> " + chain.toString() + " = " + chain.toString() + ";\n" );
/** generates SysML datatype declarations and put them at the current position (end) of avsysml */
private void dataTypes2SysML(){
if (avspec.getDataTypes() == null || avspec.getDataTypes().size() == 0) return;
avsysml.append("\n" + indentation + "// DATATYPES $$$$$$$$$$$$$$$$$$$$$$$$\n");
for(AvatarDataType dt : avspec.getDataTypes()){
// put Header
avsysml.append("\n" + indentation + "attribute def " + dataTypeSysMLname(dt.getName()) + " :> '#AvatarDataType'");
// handle fields
int nbFields = dt.attributeNb();
if (nbFields == 0)
avsysml.append(";\n");
else { // put fields.
// Note: SysML has no default values thus default values are explicitely set
AvatarAttribute aa = dt.getAttribute(i);
avsysml.append( indentation + "attribute " + fieldSysMLname(aa.getName()) + " : " );
if (aa.getType() == AvatarType.BOOLEAN) {
if (aa.hasInitialValue())
avsysml.append(" := " + aa.getInitialValue().trim() + ";\n");
else
avsysml.append(" default := " + AvatarType.BOOLEAN.getDefaultInitialValue().trim() + ";\n");
}
else if (aa.getType() == AvatarType.INTEGER) {
if (aa.hasInitialValue())
avsysml.append(" := " + aa.getInitialValue().trim() + ";\n");
else
avsysml.append(" default := " + AvatarType.INTEGER.getDefaultInitialValue().trim() + ";\n");
}
avsysml.append(aa.getDataType().getName() + ";\n"); // datatypes don't have default values
unindent(1);
avsysml.append(indentation + "}\n");
/** generates SysML declarations of communication structures and put them at the current position (end) of avsysml.
*
* Communication structures are
* <ul>
* <li> Relations, corresponding to Avatar relations </li>
* <li> Channels declarations (a channel is an inSignal/outSignal connection inside a relation) </li>
* <li> Binding of block signals to channels, to complete channel's characterization </li>
* <li> in/out Messages (structures) declarations, linking them to channels. This providing signals with profiles </li>
* </ul>
*/
private void communications2SysML(){
int nbfiforelNumber = 0;
int bfiforelNumber = 0;
int syncrelNumber = 0;
if (avspec.getRelations() == null || avspec.getRelations().size() == 0) return;
avsysml.append("\n" + indentation + "// COMMUNICATIONS $$$$$$$$$$$$$$$$$$$$$$$$\n");
// declare some parameters depending on relation type ==============
int relationType; // SYNC, FIFO or BFIFO
int relationNumber; // to distinguish relations with same characteristics
String relationConstructor; // #Sync_Rel, #Bfifo_Rel, #NBfifo_Rel (c.f. Avatar SysML library)
String relationParameters; // for the call of SysML constructors of relation parts
String channelConstructor; // #Sync, #Bfifo, #NBfifo (c.f. Avatar SysML library)
// compute parameters depending on relation type ==============
// if (ar.isAMS()) ... TODO
String blk1 = ar.getBlock1().getName();
String blk2 = ar.getBlock2().getName();
String blk1SysMLname = blockSysMLname(blk1);
String blk2SysMLname = blockSysMLname(blk2);
relationParameters = "('@block1' = " + blk1SysMLname + ", '@block2' = " + blk2SysMLname;
if (! ar.isAsynchronous()) { // sync relation
relationType = SYNC;
relationNumber = syncrelNumber++;
relationConstructor = "'#Sync_Rel'";
channelConstructor = "'#Sync'";
if(ar.isPrivate()) relationParameters += ", '@private'=true)"; // default is false in Avatar SysML library
if(ar.isPrivate()) // default: false in Avatar SysML library
if(ar.isLossy()) // default: false in Avatar SysML library
if(ar.getSizeOfFIFO() > 1) // default size: 1 in Avatar SysML library
relationParameters += ", '@private'=true, '@lossy'=true, '@max_size'=" + ar.getSizeOfFIFO() + ")";
relationParameters += ", '@private'=true, '@lossy'=true)";
if(ar.getSizeOfFIFO() > 1) // default size: 1 in Avatar SysML library
relationParameters += ", '@private'=true, '@max_size'=" + ar.getSizeOfFIFO() + ")";
relationParameters += ", '@private'=true)";
if(ar.isLossy()) // default: false in Avatar SysML library
if(ar.getSizeOfFIFO() > 1) // default size: 1 in Avatar SysML library
relationParameters += ", '@lossy'=true, '@max_size'=" + ar.getSizeOfFIFO() + ")";
relationParameters += ", '@lossy'=true)";
if(ar.getSizeOfFIFO() > 1) // default size: 1 in Avatar SysML library
relationParameters += ", '@max_size'=" + ar.getSizeOfFIFO() + ")";
if (ar.isBlocking()) { // blocking fifo relation
relationType = BFIFO;
relationNumber = bfiforelNumber++;
relationConstructor = "'#Bfifo_Rel'";
channelConstructor = "'#Bfifo'";
}
else { // non blocking fifo relation
relationType = NBFIFO;
relationNumber = nbfiforelNumber++;
relationConstructor = "'#NBfifo_Rel'";
channelConstructor = "'#NBfifo'";
}
}
// general generation (using parameters above) : put declaration to avsysml ==============
String relationSYSMLname = relationSysMLname(blk1, blk2, relationType, relationNumber);
// relation declaration --------------------
avsysml.append("\n" + indentation + "// Relation " + relationSYSMLname + "=============\n");
avsysml.append(indentation + "part " + relationSYSMLname + ": " + relationConstructor);
if(relationParameters != null)
avsysml.append(" = " + relationConstructor + relationParameters);
avsysml.append(";\n");
// Channels and associated Messages declarations ----------------
int relationSize = ar.getSignals1().size();
for(int i=0; i<relationSize; i++) { // iterate on signal connections
AvatarSignal sig1 = ar.getSignals1().get(i);
AvatarSignal sig2 = ar.getSignals2().get(i);
boolean out2in = (sig1.getInOut() == AvatarSignal.OUT);
String channelSYSMLname = channelSysMLname(channelName(blk1, blk2, sig1.getName(), sig2.getName(), out2in), relationType);
String sig1SYSMLname = signalSysMLname(sig1.getName());
String sig2SYSMLname = signalSysMLname(sig2.getName());
String message1SYSMLname = messageSysMLname(blk1,sig1.getName());
String message2SYSMLname = messageSysMLname(blk2,sig2.getName());
MethodInfo sig1Info = new MethodInfo(sig1SYSMLname, message1SYSMLname); // to collect info
MethodInfo sig2Info = new MethodInfo(sig2SYSMLname, message2SYSMLname); // to collect info
avsysml.append("\n" + indentation + "// Channel " + channelSYSMLname + "-------------\n");
avsysml.append(indentation + "part " + channelSYSMLname + " : " + channelConstructor + " = "
+ channelConstructor + "('@relation' = " + relationSYSMLname + ");\n");
// Binding block signals to the channel ................
if (out2in) { // depends on direction. symetric.
avsysml.append(indentation + "binding : '#OutSignalBinding' bind " + blk1SysMLname + "." + sig1SYSMLname + " = " + channelSYSMLname +
avsysml.append(indentation + "binding : '#InSignalBinding' bind " + blk2SysMLname + "." + sig2SYSMLname + " = " + channelSYSMLname +
avsysml.append(indentation + "binding : '#InSignalBinding' bind " + blk1SysMLname + "." + sig1SYSMLname + " = " + channelSYSMLname + ";\n");
avsysml.append(indentation + "binding : '#OutSignalBinding' bind " + blk2SysMLname + "." + sig2SYSMLname + " = " + channelSYSMLname + ";\n");
// Message declarations .........................
// one Message per direction, parallel build in two buffers msg1Buf and msg2Buf
// put declaration headers
StringBuffer msg1Buf = new StringBuffer(indentation + "\n// Message of signal " + blk1SysMLname + "." + sig1SYSMLname + "............\n");
StringBuffer msg2Buf = new StringBuffer(indentation + "\n// Message of signal " + blk2SysMLname + "." + sig2SYSMLname + "............\n");
if (out2in) {
msg1Buf.append(indentation + "part def " + message1SYSMLname + " :> '#OutMessage', " + message2SYSMLname + " {\n");
msg2Buf.append(indentation + "part def " + message2SYSMLname + " :> '#InMessage' {\n" +
indentation + indentStep + "private part '@channel' : '#Channel' = " + channelSYSMLname + ";\n");
Sophie Coudert
committed
} else {
msg1Buf.append(indentation + "part def " + message1SYSMLname + " :> '#InMessage' {\n" +
indentation + indentStep + "private part '@channel' : '#Channel' = " + channelSYSMLname + ";\n");
msg2Buf.append(indentation + "part def " + message2SYSMLname + " :> '#OutMessage', " + message1SYSMLname + " {\n");
indent(1);
// handle message fields. in-message fields redefine out-message fields
int nbFields = sig1.getListOfOriginalAttributes().size();
// parameters for handling a field
String attributeType; // SysML name associated to type
String fieldName1;
String fieldName2;
int j=0;
while (j < nbFields ) { // browse channels' fielsd
AvatarAttribute aa1 = sig1.getListOfOriginalAttributes().get(j);
// compute parameters for handling this field
// compute field type parameters
AvatarDataType dataType = null;
if (aa1.isDataType()) {
dataType = aa1.getDataType();
attributeType = dataTypeSysMLname(dataType.getName()) + ";\n";
else if (aa1.isBool()) {
attributeType = "Boolean;\n";
type = AvatarType.BOOLEAN;
}
else if (aa1.isInt()) {
attributeType = "Integer;\n";
type = AvatarType.INTEGER;
} else { attributeType = "Integer;\n"; type = AvatarType.INTEGER; } // TODO : error: SHOULD NOT BE TIMER
// compute field names
fieldName1 = fieldSysMLname(aa1.getName());
fieldName2 = fieldSysMLname(sig2.getListOfOriginalAttributes().get(j).getName());
// put field declaration
if (out2in) { // depends on direction. symetric.
Sophie Coudert
committed
msg1Buf.append(indentation + "attribute " + fieldName1 + " redefines " + fieldName2 + ";\n");
msg2Buf.append(indentation + "attribute " + fieldName2 + " : " + attributeType);
Sophie Coudert
committed
msg1Buf.append(indentation + "attribute " + fieldName1 + " : " + attributeType);
msg2Buf.append(indentation + "attribute " + fieldName2 + " redefines " + fieldName1 + ";\n");
// collect info to be used later
sig1Info.addField(fieldName1, type, dataType);
sig2Info.addField(fieldName2, type, dataType);
unindent(1);
msg1Buf.append(indentation + "}\n");
msg2Buf.append(indentation + "}\n");
// put declarations to avsysml
if (out2in) { // order only relevant for the aesthetics
avsysml.append(msg2Buf);
Sophie Coudert
committed
avsysml.append(msg1Buf);
} else {
avsysml.append(msg1Buf);
Sophie Coudert
committed
avsysml.append(msg2Buf);
methodMap.put(sig1,sig1Info);
methodMap.put(sig2,sig2Info);
/** generates SysML declarations for block methods.
* To be called while generating block declarations. Directly put generated text in avsysml.
*/
private void method2SysML(AvatarMethod am){
MethodInfo methodInfo; // to collect info
// compute return type (null for void methods)....................
String returnType; // SysML name of return type, or null
List<AvatarAttribute> returns = am.getListOfOriginalReturnAttributes(); // size must be <= 1
if(returns.size() == 0) { // void method
returnType = null;
methodInfo = new MethodInfo(methodSysMLname(am.getName()));
}
if (returns.get(0).isDataType()) {
AvatarDataType returnDataType = returns.get(0).getDataType();
returnType = dataTypeSysMLname(returns.get(0).getDataType().getName());
methodInfo = new MethodInfo(methodSysMLname(am.getName()), AvatarType.UNDEFINED, returnDataType);
}
else if (returns.get(0).isBool()) {
methodInfo = new MethodInfo(methodSysMLname(am.getName()), AvatarType.BOOLEAN, null);
} else if (returns.get(0).isInt()) {
returnType = "Integer";
methodInfo = new MethodInfo(methodSysMLname(am.getName()), AvatarType.INTEGER, null);
} else { // ERROR : TIMER, should not happen
returnType = "Integer";
methodInfo = new MethodInfo(methodSysMLname(am.getName()), AvatarType.INTEGER, null);
// put header (different for void and non-void methods).....................
avsysml.append(indentation + "action " + methodSysMLname(am.getName()) + ": '#AvatarVoidMethod'");
avsysml.append(indentation + "calc " + methodSysMLname(am.getName()) + ": '#AvatarCalcMethod'");
// put parameters and return type as fields .......................
// collect corresponding info
int nbFields = am.getListOfOriginalAttributes().size();
if (nbFields == 0 && returnType == null)
avsysml.append(";\n");
else {
avsysml.append(" {\n");
indent(1);
int j = 0;
// iterate on method parameters, put corresponding fields
while (j < nbFields) {
AvatarAttribute aa = am.getListOfOriginalAttributes().get(j);
if (aa.isDataType()) {
avsysml.append(indentation + "attribute " + fieldSysMLname(aa.getName())
+ " : " + dataTypeSysMLname(aa.getDataType().getName()) + ";\n");
methodInfo.addField(fieldSysMLname(aa.getName()), AvatarType.UNDEFINED, aa.getDataType());
} else if (aa.isInt()) {
avsysml.append(indentation + "attribute " + fieldSysMLname(aa.getName()) + " : Integer;\n");
methodInfo.addField(fieldSysMLname(aa.getName()), AvatarType.INTEGER, null);
} else if (aa.isBool()) {
avsysml.append(indentation + "attribute " + fieldSysMLname(aa.getName()) + " : Boolean;\n");
methodInfo.addField(fieldSysMLname(aa.getName()), AvatarType.BOOLEAN, null);
} else { // ERROR should not happen
avsysml.append(indentation + "attribute " + fieldSysMLname(aa.getName()) + " : Integer;\n");
methodInfo.addField(fieldSysMLname(aa.getName()), AvatarType.INTEGER, null);
}
j++;
// put return field for non-void methods
if (returnType != null)
avsysml.append(indentation + "return : " + returnType + ";\n");
unindent(1);
avsysml.append(indentation + "}\n");
methodMap.put(am, methodInfo); // memorize collected info
/** generates SysML declarations for block signals.
* To be called while generating block declarations. Directly put generated text in avsysml. Signals used in AvatarQueryOnSignal elements must
* be typed as fifos (other ones are not constrained). Thus, fifoSet must have been computed before calling this method.
*/
private void signal2SysML(AvatarSignal as){
avsysml.append(indentation + "part " + methodMap.get(as).getName() + " : " +
(fifoSet.contains(as) ? "'#Fifo'" : "'#Channel'") + ";\n");
}
/** generates SysML declarations for all blocks: iterate on specification block list */
private void blocks2SysML(){
avsysml.append("\n" + indentation + "// BLOCKS $$$$$$$$$$$$$$$$$$$$$$$$\n");
for(AvatarBlock block: avspec.getListOfBlocks())
if (block.getFather() == null) block2SysML(block);
}
/** generates SysML declarations for a blocks and direct access to inner blocks through their name (not their full path) */
private void block2SysML(AvatarBlock block){
// to memorize timers while iterating on attributes (delayed declarations)
ArrayList<AvatarAttribute> timerList = new ArrayList<AvatarAttribute>();
blocklink(); // to directly access inner blocks through their (short) name
// put block header --------------------
avsysml.append("\n" + indentation + "// Block " + blockSYSMLname + "=============\n");
avsysml.append(indentation + "part " + blockSYSMLname + " : '#AvatarBlock' {\n");
indent(1);
// put attribute declarations ----------------------------
// no default value in SysML, thus default values are set explicitly
// timer attributes are memorized to be declared later
if (block.getAttributes() != null && block.getAttributes().size() != 0) {
avsysml.append("\n" + indentation + "// Attributes ---------------------\n");
int nbAttributes = block.getOriginalAttributes().size();
while(j < nbAttributes) { // iterate on block's attributes
AvatarAttribute aa = block.getOriginalAttributes().get(j);
if (aa.isDataType()) {
avsysml.append(indentation + "attribute " + attributeSysMLname(aa.getName()) +
" : " + dataTypeSysMLname(aa.getDataType().getName()) + ";\n");
avsysml.append(indentation + "attribute " + attributeSysMLname(aa.getName()) + " : Integer");
if (aa.hasInitialValue())
avsysml.append(" := " + aa.getInitialValue().trim());
else
avsysml.append(" default := " + AvatarType.INTEGER.getDefaultInitialValue().trim());
avsysml.append(indentation + "attribute " + attributeSysMLname(aa.getName()) + " : Boolean");
if (aa.hasInitialValue())
avsysml.append(" := " + aa.getInitialValue().trim());
else
avsysml.append(" default := " + AvatarType.BOOLEAN.getDefaultInitialValue().trim());
avsysml.append(";\n");
}
else if (aa.isTimer()) {
timerList.add(aa);
} else {} // TODO : should not happen. to remove if not possible
// put constant declarations --------------------
if (block.getConstants() != null && block.getConstants().size() != 0) {
avsysml.append("\n" + indentation + "// Constants ---------------------\n");
int j = 0;
int nbConstants = block.getConstants().size();
while(j < nbConstants) { // iterate on block's constants
AvatarAttribute aa = block.getOriginalAttributes().get(j);
if (aa.isDataType()) {
avsysml.append(indentation + "readolny attribute " + attributeSysMLname(aa.getName()) +
" : " + dataTypeSysMLname(aa.getDataType().getName()) + ";\n");
}
else if (aa.isInt()) {
avsysml.append(indentation + "readolny attribute " + attributeSysMLname(aa.getName()) + " : Integer");
if (aa.hasInitialValue())
avsysml.append(" := " + aa.getInitialValue().trim());
else
avsysml.append(" default := " + AvatarType.INTEGER.getDefaultInitialValue().trim());
avsysml.append(indentation + "readolny attribute " + attributeSysMLname(aa.getName()) + " : Boolean");
if (aa.hasInitialValue())
avsysml.append(" := " + aa.getInitialValue().trim());
else
avsysml.append(" default := " + AvatarType.BOOLEAN.getDefaultInitialValue().trim());
else {} // TODO ? error should not happen (timers arn't constants...)
// put method declarations --------------------
if (block.getMethods() != null && block.getMethods().size() != 0) {
avsysml.append("\n" + indentation + "// Methods ---------------------\n");
for (AvatarMethod am : block.getMethods()) method2SysML(am);
}
// put signal declarations --------------------
if (block.getSignals() != null && block.getSignals().size() != 0) {
avsysml.append("\n" + indentation + "// Signals ---------------------\n");
for (AvatarSignal as : block.getSignals()) signal2SysML(as);
}
// put timer declarations -------------------
if (timerList != null && timerList.size() != 0) {
avsysml.append("\n" + indentation + "// Timers ---------------------\n");
avsysml.append(indentation + "part " + timerBlockSysMLname(timer.getName()) + ": '#AvatarTimer' = '#AvatarTimer'();\n");
// put state-machine description --------------------
avsysml.append("\n" + indentation + "// state-machine -------------------\n");
List<AvatarBlock> subBlockList = new ArrayList<AvatarBlock>();
for(AvatarBlock blk: avspec.getListOfBlocks()) { if (blk.getFather() == block) subBlockList.add(blk); }
if (subBlockList.size() != 0) {
avsysml.append("\n" + indentation + "// Sub-Blocks øøøøøøøøøøøøøøøøøøøøøøø\n");
for (AvatarBlock blk : subBlockList) block2SysML(blk);
unindent(1);
avsysml.append(indentation + "}\n");
/** generates state information for each state machine element of the specification and technically
* added states (before some communication elements). Put this information in a map which is returned.
*/
private HashMap<AvatarStateMachineElement, StateInfo> computeStateInfo(AvatarStateMachine asm) {
// the map to fill and return
HashMap<AvatarStateMachineElement, StateInfo> stateMap = new HashMap<AvatarStateMachineElement, StateInfo>();
// associate names to future SysML states.........................
// number to identify states in an unambigous way
int randomNumber = 0;
int countNumber = 0;
int sendNumber = 0;
int receiveNumber = 0;
int setNumber = 0;
int resetNumber = 0;
int expireNumber = 0;
// produces and memorize stateinfo structure (couple name, prename) for all state machine element
for (AvatarStateMachineElement asme : asm.getListOfElements()) {
StateInfo stateinfo;
// states without communication hav just a name.
if (asme instanceof AvatarStartState)
stateinfo = new StateInfo(standardStateSysMLname(asme.getName()));
else if (asme instanceof AvatarQueryOnSignal)
stateinfo = new StateInfo(countStateSysMLname(((AvatarQueryOnSignal) asme).getSignal().getName(), countNumber++));
else if (asme instanceof AvatarRandom)
stateinfo = new StateInfo(randomStateSysMLname(randomNumber++));
// next cases rely on communication and thus, are subject to the introduction of an additional "preceding" state.
if (((AvatarActionOnSignal) asme).isSending())
sendStateSysMLname(((AvatarActionOnSignal) asme).getSignal().getName(), sendNumber),
presendStateSysMLname(((AvatarActionOnSignal) asme).getSignal().getName(), sendNumber++));
stateinfo = new StateInfo(receiveStateSysMLname(((AvatarActionOnSignal) asme).getSignal().getName(), receiveNumber),
prereceiveStateSysMLname(((AvatarActionOnSignal) asme).getSignal().getName(), receiveNumber++));
} else if (asme instanceof AvatarSetTimer) {
stateinfo = new StateInfo(setTimerStateSysMLname(((AvatarTimerOperator) asme).getTimer().getName(), setNumber),
presetTimerStateSysMLname(((AvatarTimerOperator) asme).getTimer().getName(), setNumber++));
} else if (asme instanceof AvatarResetTimer) {
stateinfo = new StateInfo(resetTimerStateSysMLname(((AvatarTimerOperator) asme).getTimer().getName(), resetNumber),
preresetTimerStateSysMLname(((AvatarTimerOperator) asme).getTimer().getName(), resetNumber++));
} else if (asme instanceof AvatarExpireTimer) {
stateinfo = new StateInfo(expireTimerStateSysMLname(((AvatarTimerOperator) asme).getTimer().getName(), expireNumber),
preexpireTimerStateSysMLname(((AvatarTimerOperator) asme).getTimer().getName(), expireNumber++));
} else continue; // TODO ? curious states "AvatarEmpty" not handled
return stateMap;
}
/** generates SysML description of state machine */
private void statemachine2SysML(AvatarStateMachine asm) {
HashMap<AvatarStateMachineElement, StateInfo> stateMap = computeStateInfo(asm);
// put state-machine header to avsysml.............................
avsysml.append(indentation + "exhibit state '@statemachine' : '#AvatarStateMachine' {\n");
indent(1);
// put SysML states descriptions with associated transition descriptions.........
stateMap.forEach(new State2SysML(stateMap));
unindent(1);
avsysml.append(indentation + "}\n");
/** buffer to build SysML declarations of outgoing transitions from one state(filled by method transitionsAndRequests) */
private StringBuffer sysMLtransitions = new StringBuffer();
/** buffer to build in-a-state requests associated to the outgoing transitions of this state (filled by method transitionsAndRequests) */
private StringBuffer sysMLrequests = new StringBuffer();
/** communication (and timer) states that require an added state before (as they have incomming transitions with action, from the currently
* handled state) (filled by method transitionsAndRequests) */
private List<AvatarStateMachineElement> requirePreCom = new ArrayList<AvatarStateMachineElement>();
/** to iterate on the state machine elements of one block. An iteration puts a state declaration in avsysml, followed by the declarations of
* its outgoing transitions. If the needed technically added pre-communication are detected while handling these transitions. The declarations
* of these added states are added after the transition declarations, followed by their own single outgoing transition.
*/
private class State2SysML implements BiConsumer<AvatarStateMachineElement, StateInfo> {
/** provides all states with name information */
HashMap<AvatarStateMachineElement, StateInfo> stateMap;
/** false untill stopState has been encountered (as it can be encountered several times but generated only once) */
Boolean stopStateDone;
public State2SysML(HashMap<AvatarStateMachineElement, StateInfo> _stateMap) {
stateMap = _stateMap;
stopStateDone = false;
}
/** puts a state declaration in avsysml, followed by the declarations of
* its outgoing transitions. If the needed technically added pre-communication are detected while handling these transitions. The declarations
* of these added states are added after the transition declarations, followed by their own single outgoing transition.
*/
public void accept(AvatarStateMachineElement asme, StateInfo info) {
// compute transition declarations and request descriptions for the outgoing transitions of the state
// identify states that require an added pre-communication state
transitionsAndRequests(info.getName(), asme.getNexts(), ((asme instanceof AvatarState) ? "'@pool'" : "'@request'"), stateMap);
String requests = sysMLrequests.toString(); // to put after state declaration
// put state Descriptions ................................
// depending on state type
if(asme instanceof AvatarState){
avsysml.append("\n" + indentation + "state " + info.getName() + " : '#AvatarStandardState'");
avsysml.append(";\n");
avsysml.append(" = '#AvatarStandardState'(\n" + requests + "\n" + indentation + ");\n");
} else
if(asme instanceof AvatarRandom){ // specific: assign a random value to a variable
avsysml.append("\n" + indentation + "state " + info.getName() + " : '#AvatarRandomState' = '#AvatarRandomState'(\n");
if (!requests.equals("")) avsysml.append(requests + ",\n"); // put request description (none means default request)
indent(1);
avsysml.append(indentation + "'@state_action' = '#Assignment'(\n");
indent(1);
// the variable to be assigned
avsysml.append(indentation + "'@target' = " + attributeSysMLname(((AvatarRandom)asme).getVariable()) + ",\n");
// the random value to assign
avsysml.append(indentation + "'@value' = '#bound_random'(" +
expr2SysML(((AvatarRandom)asme).getMinValue().replaceAll("__",".")) + ", " +
expr2SysML(((AvatarRandom)asme).getMaxValue().replaceAll("__",".")) +")\n");
unindent(1);
avsysml.append(indentation + ")\n");
unindent(1);
avsysml.append(indentation + ");\n");
} else
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
if(asme instanceof AvatarQueryOnSignal){ // specific: assign the content size of a signal to a variable
avsysml.append("\n" + indentation + "state " + info.getName() + " : '#AvatarCountState' = '#AvatarCountState'(\n");
if (!requests.equals("")) avsysml.append(requests + ",\n"); // put request description (none means default request)
indent(1);
avsysml.append(indentation + "'@state_action' = '#Assignment'(\n");
indent(1);
// the variable to assign
avsysml.append(indentation + "'@target' = " + attributeSysMLname(((AvatarQueryOnSignal)asme).getAttribute().getName()) + ",\n");
// the size of the content of the concerned signal
avsysml.append(indentation + "'@value' = " + methodMap.get(((AvatarQueryOnSignal)asme).getSignal()).getName() + ".'@amount'()\n");
unindent(1);
avsysml.append(indentation + ")\n");
unindent(1);
avsysml.append(indentation + ");\n");
} else
if(asme instanceof AvatarActionOnSignal){
if(((AvatarActionOnSignal)asme).isSending()) {
avsysml.append("\n" + indentation + "state " + info.getName() + " : '#AvatarSendState'");
if (requests.equals("")) // default request
avsysml.append(";\n");
else // put requests description
avsysml.append(" = '#AvatarSendState'(\n" + requests + "\n" + indentation + ");\n");
} else {
avsysml.append("\n" + indentation + "state " + info.getName() + " : '#AvatarReceiveState'");
if (requests.equals("")) // default request
avsysml.append(";\n");
else
avsysml.append(" = '#AvatarReceiveState'(\n" + requests + "\n" + indentation + ");\n");
}
} else
if(asme instanceof AvatarStartState){
avsysml.append("\n" + indentation + "entry action " + info.getName() + " :'#AvatarStartState'");
if (requests.equals("")) // default request
avsysml.append(";\n");
else // put requests description
avsysml.append(" = '#AvatarStartState'(\n" + requests + "\n" + indentation + ");\n");
} else
if(asme instanceof AvatarStopState){ // specific mandatory empty request list (implicite)
if(!stopStateDone)
avsysml.append("\n" + indentation + "exit action " + info.getName() + " :'#AvatarStopState';\n");
stopStateDone = true;
} else
if(asme instanceof AvatarSetTimer){
avsysml.append("\n" + indentation + "state " + info.getName() + " : '#AvatarSetTimerState'");
if (requests.equals("")) // default request
avsysml.append(";\n");
else // put requests description
avsysml.append(" = '#AvatarSetTimerState'(\n" + requests + "\n" + indentation + ");\n");
} else
if(asme instanceof AvatarResetTimer){
avsysml.append("\n" + indentation + "state " + info.getName() + " : '#AvatarResetTimerState'");
if (requests.equals("")) // default request
avsysml.append(";\n");
else // put requests description
avsysml.append(" = '#AvatarResetTimerState'(\n" + requests + "\n" + indentation + ");\n");
} else
if(asme instanceof AvatarExpireTimer){
avsysml.append("\n" + indentation + "state " + info.getName() + " : '#AvatarExpireTimerState'");
if (requests.equals("")) // default request
avsysml.append(";\n");
else // put requests description
avsysml.append(" = '#AvatarExpireTimerState'(\n" + requests + "\n" + indentation + ");\n");
}
// put transition declarations .................................................
avsysml.append(sysMLtransitions);
// put pre-communication states to add and their single outgoing transition
for (AvatarStateMachineElement aos: requirePreCom) {
// the name of an added states is obtained by StateInfo.getPreName()
// the target of its outgoing transition is the communication state itself (StateInfo.getName())
// endTransition adds distribution law information at the end of the transition declarations
StateInfo stateinfo = stateMap.get(aos);
if (aos instanceof AvatarActionOnSignal) {
MethodInfo signalinfo = methodMap.get(((AvatarActionOnSignal)aos).getSignal());
if (((AvatarActionOnSignal)aos).isSending()) {
// put pre-communication State
avsysml.append("\n" + indentation + "state " + stateinfo.getPreName() + " : '#AvatarPreSendState' = '#AvatarPreSendState' (\n");
indent(1);
avsysml.append(indentation + "'@request' = {\n");
indent(1);
// sending request from pre-send state to send state
avsysml.append(sendRequest2SysML(1, "0", "0", signalinfo, ((AvatarActionOnSignal)aos).getOriginalValues()) + "\n");
unindent(1);
avsysml.append(indentation + "}\n");
unindent(1);
avsysml.append(indentation + ");\n");
// transition from pre-send state to send state
avsysml.append("\n" + indentation + "transition : '#AvatarTransition' first " + stateinfo.getPreName() +
" then " + stateinfo.getName() +
endTransition(0,"","", 1));
} else {
// put pre-communication State
avsysml.append("\n" + indentation + "state " + stateinfo.getPreName() + " : '#AvatarPreReceiveState' = '#AvatarPreReceiveState' (\n");
indent(1);
avsysml.append(indentation + "'@request' = {\n");
indent(1);
// receiving request from pre-receive state to receive state
avsysml.append(receiveRequest2SysML(1, "0", "0", signalinfo.getName()) + "\n");
unindent(1);
avsysml.append(indentation + "}\n");
unindent(1);
avsysml.append(indentation + ");\n");
// transition from pre-receive state to receive state
avsysml.append("\n" + indentation + "transition : '#AvatarTransition' first " + stateinfo.getPreName() + "\n");
indent(1);
// updating target variables with received values
String doAction = receiveActions2SysML(signalinfo, ((AvatarActionOnSignal)aos).getOriginalValues());
if (doAction.length() == 0) // receive simple signal (without carried value)
avsysml.append(indentation + "then " + stateinfo.getName() +
endTransition(0,"","", 1));
else { // put updating action
avsysml.append(doAction);
avsysml.append(" then " + stateinfo.getName() +
endTransition(0,"","", 1));
}
unindent(1);
} else if (aos instanceof AvatarSetTimer) { // a special kind of send request
// put pre-communication State
avsysml.append("\n" + indentation + "state " + stateinfo.getPreName() + " : '#AvatarPreSendState' = '#AvatarPreSendState' (\n");
indent(1);
avsysml.append(indentation + "'@request' = {\n");
// put the specific sending request, carrying a value
avsysml.append(setTimerRequest2SysML(1, "0", "0",