diff --git a/src/main/java/ui/atd/AttackTreeDiagramPanel.java b/src/main/java/ui/atd/AttackTreeDiagramPanel.java index 19f6d59ecf11f756bdcc1b6df5eb57ebaae8d651..8e94a378231d5a2102d285afe66b7c84d97426c1 100644 --- a/src/main/java/ui/atd/AttackTreeDiagramPanel.java +++ b/src/main/java/ui/atd/AttackTreeDiagramPanel.java @@ -86,7 +86,8 @@ public class AttackTreeDiagramPanel extends TDiagramPanel implements TDPWithAttr "A root attack must not be connected to a parent operator", "Each attack should be connected by exactly one path to the root attack"}; - public static String[] syntaxRulesOfOperators = {"An operator node must have at least two children attack nodes", + public static String[] syntaxRulesOfOperators = { + "An operator node must have at least two children attack nodes", "An operator node must have only one parent attack node", "An operator node must be only one of the the following types: SEQUENTIAL, AND, or OR", "An operator node must not have the root attack as a child node"}; @@ -505,6 +506,104 @@ public class AttackTreeDiagramPanel extends TDiagramPanel implements TDPWithAttr return map; } + public int getNbOfSubAttacks(ATDConstraint constraint) { + int count = 0; + for(TGComponent tgc: getAllComponentList()) { + if (tgc instanceof ATDAttackConnector) { + if (((ATDAttackConnector) tgc).getTGComponent2() == constraint) { + if (((ATDAttackConnector) tgc).getTGComponent1() instanceof ATDAttack) { + count ++; + } + } + } + } + return count; + } + + public int getNumberOfAttackParentNode(ATDConstraint constraint) { + int count = 0; + for(TGComponent tgc: getAllComponentList()) { + if (tgc instanceof ATDAttackConnector) { + if (((ATDAttackConnector) tgc).getTGComponent1() == constraint) { + if (((ATDAttackConnector) tgc).getTGComponent2() instanceof ATDAttack) { + count ++; + } + } + } + } + return count; + } + + public boolean hasRootAttackAsChild(ATDConstraint constraint) { + + for(TGComponent tgc: getAllComponentList()) { + if (tgc instanceof ATDAttackConnector) { + if (((ATDAttackConnector) tgc).getTGComponent2() == constraint) { + if (((ATDAttackConnector) tgc).getTGComponent1() instanceof ATDAttack) { + ATDAttack attack = (ATDAttack) ((ATDAttackConnector) tgc).getTGComponent1(); + if (attack.isRootAttack()) { + return true; + } + } + } + } + } + + return false; + } + + public ATDAttack getParentAttack(ATDConstraint constraint) { + + for(TGComponent tgc: getAllComponentList()) { + if (tgc instanceof ATDAttackConnector) { + if (((ATDAttackConnector) tgc).getTGComponent2() == constraint) { + if (((ATDAttackConnector) tgc).getTGComponent1() instanceof ATDAttack) { + ATDAttack attack = (ATDAttack) ((ATDAttackConnector) tgc).getTGComponent1(); + return attack; + } + } + } + } + + return null; + } + + + public boolean checkOperatorRule(ATDConstraint constraint, int ruleIndex) { + + if (ruleIndex == 0) { + int nb = getNbOfSubAttacks(constraint); + return nb > 1; + + } else if (ruleIndex == 1) { + return getNumberOfAttackParentNode(constraint) == 1; + + } else if (ruleIndex == 2) { + return constraint.isSequence() || constraint.isAND() || constraint.isOR(); + + } else if (ruleIndex == 3) { + return !hasRootAttackAsChild(constraint); + } + return false; + } + public HashMap<ATDConstraint, ArrayList<Boolean>> computeSyntaxRulesForOperators() { + HashMap<ATDConstraint, ArrayList<Boolean>> map = new HashMap<>(); + + for(TGComponent tgc: getAllComponentList()) { + if (tgc instanceof ATDConstraint) { + @SuppressWarnings("unchecked") + ArrayList<Boolean> list = new ArrayList(syntaxRulesOfOperators.length); + for(int i=0; i<syntaxRulesOfOperators.length; i++) { + boolean b = checkOperatorRule((ATDConstraint)tgc, i); + list.add(b); + } + map.put((ATDConstraint)tgc, list); + } + } + + return map; + } + public int getNbOfRootAttacks() { int count = 0; for(TGComponent tgc: getAllComponentList()) { @@ -553,6 +652,30 @@ public class AttackTreeDiagramPanel extends TDiagramPanel implements TDPWithAttr } } + sb.append(CR); + HashMap<ATDConstraint, ArrayList<Boolean>> mapOfSyntaxForConstraints = computeSyntaxRulesForOperators(); + for(ATDConstraint constraint: mapOfSyntaxForConstraints.keySet()) { + String name = constraint.getValue(); + ATDAttack attack = getParentAttack(constraint); + if (attack != null) { + name += " with parent attack: " + attack.getAttackName(); + } + sb.append("- constraint " + name); + int nbOfTrue = 0; + ArrayList<Boolean> list = mapOfSyntaxForConstraints.get(constraint); + String notRespected = ""; + for(int i=0; i<list.size(); i++) { + if (list.get(i)) { nbOfTrue++; } else { + notRespected += " " + (i+1); + } + } + if (nbOfTrue == syntaxRulesOfOperators.length) { + sb.append(" respects all syntax rules" + CR); + } else { + sb.append(" does NOT respect rules: " + notRespected.trim() + ". ERROR" + CR); + } + } + sb.append(CR + CR + CR + "# Definition of Metrics" + CR + CR); sb.append(CR + "## Semantic correctness: (ra + ro) / complexity" + CR); @@ -568,11 +691,22 @@ public class AttackTreeDiagramPanel extends TDiagramPanel implements TDPWithAttr sb.append("- Tvo: the sum of for each operator node, the number of respected syntax rules divided by the total number of operator node syntax rules" + CR); sb.append(CR + "## Syntax rules of attack trees" + CR); - sb.append("- Each attack tree should have exactly one root attack" + CR); - sb.append("Each attack should be connected by exactly one path to the root attack" + CR); + for(int i=0; i<syntaxRulesOfAttackTree.length; i++) { + sb.append((i+1) + ". " + syntaxRulesOfAttackTree[i] + CR); + } sb.append(CR + "## Syntax rules of attack nodes" + CR); - sb.append("- Each attack node (including the root attack) must include a title" + CR); + for(int i=0; i<syntaxRulesOfAttacks.length; i++) { + sb.append((i+1) + ". " + syntaxRulesOfAttacks[i] + CR); + } + + sb.append(CR + "## Syntax rules of operator nodes" + CR); + for(int i=0; i<syntaxRulesOfOperators.length; i++) { + sb.append((i+1) + ". " + syntaxRulesOfOperators[i] + CR); + } + + + /*sb.append("- Each attack node (including the root attack) must include a title" + CR); sb.append("- Each attack node must include a short description, explaining what the attack node represents" + CR); sb.append("- The title of an attack node must include only alphanumeric characters (i.e. no white-spaces)" + CR); sb.append("- An attack node will only be connected to operator nodes" + CR); @@ -582,7 +716,7 @@ public class AttackTreeDiagramPanel extends TDiagramPanel implements TDPWithAttr sb.append("An operator node must have at least two children attack nodes" + CR); sb.append("An operator node must have only one parent attack node" + CR); sb.append("An operator node must be only one of the the following types: SEQUENTIAL, AND, or OR" + CR); - sb.append("An operator node must not have the root attack as a child node" + CR); + sb.append("An operator node must not have the root attack as a child node" + CR);*/ sb.append(CR + "## Format of CSV" + CR + "attack_tree_name,complexity,num_relevant_attack_nodes,num_relevant_operator_nodes," + "num_absent_attack_nodes,num_absent_operator_nodes,semantic_correctness,completeness,syntaxic_correctness" + CR);