diff --git a/bundles/cnf/releaserepo/index.xml.sha b/bundles/cnf/releaserepo/index.xml.sha
deleted file mode 100644
index 07ba11363..000000000
--- a/bundles/cnf/releaserepo/index.xml.sha
+++ /dev/null
@@ -1 +0,0 @@
-0400d6060920df51e4069b81cd760256a0e891a20f37e9dc0a06c4d05a97367b
diff --git a/bundles/specmate-cause-effect-patterns/.classpath b/bundles/specmate-cause-effect-patterns/.classpath
index 2d7348660..c790fdc43 100644
--- a/bundles/specmate-cause-effect-patterns/.classpath
+++ b/bundles/specmate-cause-effect-patterns/.classpath
@@ -1,11 +1,11 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bundles/specmate-integration-test/.classpath b/bundles/specmate-integration-test/.classpath
index cce7ccc85..59c129156 100644
--- a/bundles/specmate-integration-test/.classpath
+++ b/bundles/specmate-integration-test/.classpath
@@ -1,12 +1,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bundles/specmate-integration-test/resources/test_rules.objectif b/bundles/specmate-integration-test/resources/test_rules.objectif
index 6b969e482..9e51fa68c 100644
--- a/bundles/specmate-integration-test/resources/test_rules.objectif
+++ b/bundles/specmate-integration-test/resources/test_rules.objectif
@@ -1,4 +1,5 @@
-WENN A=5 UND B=3 DANN C=7 ENDE-WENN
+WENN A=5 UND X=9 DANN C=7 ENDE-WENN
WENN X = Z ODER Y>4 DANN F="Test" ENDE-WENN
WENN A=1 DANN WENN B=1 DANN C=1 ENDE-WENN ENDE-WENN
-WENN A=1 DANN B=1 SONST C=2 ENDE-WENN
\ No newline at end of file
+WENN A=1 DANN B=1 SONST C=2 ENDE-WENN
+WENN A=1 DANN WENN B=1 DANN C=1 SONST C=2 ENDE-WENN ENDE-WENN
\ No newline at end of file
diff --git a/bundles/specmate-integration-test/src/com/specmate/test/integration/ObjectifTest.java b/bundles/specmate-integration-test/src/com/specmate/test/integration/ObjectifTest.java
index 597ba4e44..96c17052e 100644
--- a/bundles/specmate-integration-test/src/com/specmate/test/integration/ObjectifTest.java
+++ b/bundles/specmate-integration-test/src/com/specmate/test/integration/ObjectifTest.java
@@ -7,9 +7,14 @@
import java.util.List;
import org.eclipse.emf.common.util.URI;
+import org.json.JSONArray;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
+import com.specmate.model.requirements.CEGModel;
+import com.specmate.model.requirements.CEGNode;
+import com.specmate.model.requirements.NodeType;
+import com.specmate.model.requirements.RequirementsFactory;
import com.specmate.objectif.resolve.BusinessRuleUtil;
import com.specmate.objectif.resolve.rule.AndNode;
import com.specmate.objectif.resolve.rule.BusinessRuleNode;
@@ -18,95 +23,267 @@
import com.specmate.objectif.resolve.rule.OrNode;
import com.specmate.xtext.XTextException;
-public class ObjectifTest {
+// Two types of tests:
+// 1) tests for checking the functionality of the xtext parsing
+// 2) tests for checking the functionality of the pseudo code translator
+public class ObjectifTest extends ModelGenerationTestBase {
+
+ public ObjectifTest() throws Exception {
+ super();
+ }
+
+ // Unit tests for the Xtext Parsing
@Test
public void testLoadRules() throws URISyntaxException, XTextException {
List rules = loadRules("/resources/test_rules.objectif");
- Assert.assertTrue(rules.size() == 4);
+ Assert.assertTrue(rules.size() == 5);
}
-
+
@Test
public void testAND() throws URISyntaxException, XTextException {
List rules = loadRules("/resources/test_rules.objectif");
BusinessRuleNode rule = rules.get(0);
ObjectifNode cause = rule.getCause();
Assert.assertTrue(cause instanceof AndNode);
-
- ObjectifNode causeA = ((AndNode)cause).getLeft();
- ObjectifNode causeB = ((AndNode)cause).getRight();
+
+ ObjectifNode causeA = ((AndNode) cause).getLeft();
+ ObjectifNode causeB = ((AndNode) cause).getRight();
Assert.assertTrue(causeA instanceof LiteralNode);
- Assert.assertTrue(((LiteralNode)causeA).getContent().equals("A=5"));
+ Assert.assertTrue(((LiteralNode) causeA).getContent().equals("A=5"));
Assert.assertTrue(causeB instanceof LiteralNode);
- Assert.assertTrue(((LiteralNode)causeB).getContent().equals("B=3"));
-
+ Assert.assertTrue(((LiteralNode) causeB).getContent().equals("X=9"));
+
ObjectifNode effect = rule.getEffect();
Assert.assertTrue(effect instanceof LiteralNode);
- Assert.assertTrue(((LiteralNode)effect).getContent().equals("C=7"));
+ Assert.assertTrue(((LiteralNode) effect).getContent().equals("C=7"));
}
-
+
@Test
public void testOR() throws URISyntaxException, XTextException {
List rules = loadRules("/resources/test_rules.objectif");
BusinessRuleNode rule = rules.get(1);
ObjectifNode cause = rule.getCause();
Assert.assertTrue(cause instanceof OrNode);
-
- ObjectifNode causeA = ((OrNode)cause).getLeft();
- ObjectifNode causeB = ((OrNode)cause).getRight();
+
+ ObjectifNode causeA = ((OrNode) cause).getLeft();
+ ObjectifNode causeB = ((OrNode) cause).getRight();
Assert.assertTrue(causeA instanceof LiteralNode);
- Assert.assertTrue(((LiteralNode)causeA).getContent().equals("X = Z"));
+ Assert.assertTrue(((LiteralNode) causeA).getContent().equals("X = Z"));
Assert.assertTrue(causeB instanceof LiteralNode);
- Assert.assertTrue(((LiteralNode)causeB).getContent().equals("Y>4"));
-
+ Assert.assertTrue(((LiteralNode) causeB).getContent().equals("Y>4"));
+
ObjectifNode effect = rule.getEffect();
Assert.assertTrue(effect instanceof LiteralNode);
- Assert.assertTrue(((LiteralNode)effect).getContent().equals("F=\"Test\""));
+ Assert.assertTrue(((LiteralNode) effect).getContent().equals("F=\"Test\""));
}
-
+
@Test
public void testNesting() throws URISyntaxException, XTextException {
List rules = loadRules("/resources/test_rules.objectif");
BusinessRuleNode rule = rules.get(2);
ObjectifNode cause = rule.getCause();
Assert.assertTrue(cause instanceof LiteralNode);
- Assert.assertTrue(((LiteralNode)cause).getContent().equals("A=1"));
-
+ Assert.assertTrue(((LiteralNode) cause).getContent().equals("A=1"));
+
ObjectifNode effect = rule.getEffect();
Assert.assertTrue(effect instanceof BusinessRuleNode);
-
- BusinessRuleNode ruleB = (BusinessRuleNode) effect;
-
+
+ BusinessRuleNode ruleB = (BusinessRuleNode) effect;
+
ObjectifNode causeB = ruleB.getCause();
Assert.assertTrue(causeB instanceof LiteralNode);
- Assert.assertTrue(((LiteralNode)causeB).getContent().equals("B=1"));
-
+ Assert.assertTrue(((LiteralNode) causeB).getContent().equals("B=1"));
+
ObjectifNode effectB = ruleB.getEffect();
Assert.assertTrue(effectB instanceof LiteralNode);
- Assert.assertTrue(((LiteralNode)effectB).getContent().equals("C=1"));
+ Assert.assertTrue(((LiteralNode) effectB).getContent().equals("C=1"));
}
-
+
@Test
public void testAlternative() throws URISyntaxException, XTextException {
List rules = loadRules("/resources/test_rules.objectif");
BusinessRuleNode rule = rules.get(3);
ObjectifNode cause = rule.getCause();
Assert.assertTrue(cause instanceof LiteralNode);
- Assert.assertTrue(((LiteralNode)cause).getContent().equals("A=1"));
+ Assert.assertTrue(((LiteralNode) cause).getContent().equals("A=1"));
ObjectifNode effect = rule.getEffect();
Assert.assertTrue(effect instanceof LiteralNode);
- Assert.assertTrue(((LiteralNode)effect).getContent().equals("B=1"));
-
+ Assert.assertTrue(((LiteralNode) effect).getContent().equals("B=1"));
+
Assert.assertTrue(rule.hasAlternative());
ObjectifNode alternative = rule.getAlternative();
Assert.assertTrue(alternative instanceof LiteralNode);
- Assert.assertTrue(((LiteralNode)alternative).getContent().equals("C=2"));
+ Assert.assertTrue(((LiteralNode) alternative).getContent().equals("C=2"));
+ }
+
+ @Test
+ public void testAlternativeCombinedWithNesting() throws URISyntaxException, XTextException {
+ List rules = loadRules("/resources/test_rules.objectif");
+ BusinessRuleNode rule = rules.get(4);
+ ObjectifNode cause = rule.getCause();
+ Assert.assertTrue(cause instanceof LiteralNode);
+ Assert.assertTrue(((LiteralNode) cause).getContent().equals("A=1"));
+ ObjectifNode effect = rule.getEffect();
+ Assert.assertTrue(effect instanceof BusinessRuleNode);
+ BusinessRuleNode ruleB = (BusinessRuleNode) effect;
+
+ ObjectifNode causeB = ruleB.getCause();
+ Assert.assertTrue(causeB instanceof LiteralNode);
+ Assert.assertTrue(((LiteralNode) causeB).getContent().equals("B=1"));
+
+ ObjectifNode effectB = ruleB.getEffect();
+ Assert.assertTrue(effectB instanceof LiteralNode);
+ Assert.assertTrue(((LiteralNode) effectB).getContent().equals("C=1"));
+
+ Assert.assertTrue(ruleB.hasAlternative());
+ ObjectifNode alternative = ruleB.getAlternative();
+ Assert.assertTrue(alternative instanceof LiteralNode);
+ Assert.assertTrue(((LiteralNode) alternative).getContent().equals("C=2"));
+
+ }
+
+ // Unit tests for the pseudo code translation
+ @Test
+ public void testModelGenerationSimplePseudoCode() {
+ String text = "WENN x DANN y ENDE-WENN";
+ RequirementsFactory f = RequirementsFactory.eINSTANCE;
+ CEGModel model = f.createCEGModel();
+ CEGNode node1 = createNode(model, "BR1", "is present", NodeType.OR);
+ CEGNode node2 = createNode(model, "x", "is present", null);
+ CEGNode node3 = createNode(model, "y", "is present", null);
+ createConnection(model, node1, node3, false);
+ createConnection(model, node2, node1, false);
+ JSONArray generated = generateCEGWithModelRequirementsText(text);
+ checkResultingModel(generated, model);
+ }
+
+ @Test
+ public void testModelGenerationPseudoCodeWithInterconnectedCauses() {
+ String text = "WENN x UND y UND z ODER w DANN effekt ENDE-WENN";
+ RequirementsFactory f = RequirementsFactory.eINSTANCE;
+ CEGModel model = f.createCEGModel();
+ CEGNode node1 = createNode(model, "BR1", "is present", NodeType.OR);
+ CEGNode node2 = createNode(model, "x", "is present", null);
+ CEGNode node3 = createNode(model, "y", "is present", null);
+ CEGNode node4 = createNode(model, "z", "is present", null);
+ CEGNode node5 = createNode(model, "w", "is present", null);
+ CEGNode node6 = createNode(model, "effekt", "is present", null);
+ CEGNode node7 = createNode(model, "Intermediate Node1", "is present", NodeType.AND);
+ createConnection(model, node2, node7, false);
+ createConnection(model, node3, node7, false);
+ createConnection(model, node4, node7, false);
+ createConnection(model, node5, node1, false);
+ createConnection(model, node7, node1, false);
+ createConnection(model, node1, node6, false);
+ JSONArray generated = generateCEGWithModelRequirementsText(text);
+ checkResultingModel(generated, model);
+ }
+
+ @Test
+ public void testModelGenerationPseudoCodeWithInterconnectedCausesAndSingleNesting() {
+ String text = "WENN x UND y UND z ODER w DANN WENN xB ODER yB DANN effekt ENDE-WENN ENDE-WENN";
+ RequirementsFactory f = RequirementsFactory.eINSTANCE;
+ CEGModel model = f.createCEGModel();
+ CEGNode node1 = createNode(model, "BR1", "is present", NodeType.OR);
+ CEGNode node2 = createNode(model, "x", "is present", null);
+ CEGNode node3 = createNode(model, "y", "is present", null);
+ CEGNode node4 = createNode(model, "z", "is present", null);
+ CEGNode node5 = createNode(model, "w", "is present", null);
+ CEGNode node7 = createNode(model, "Intermediate Node1", "is present", NodeType.AND);
+
+ CEGNode node8 = createNode(model, "BR2", "is present", NodeType.AND);
+ CEGNode node9 = createNode(model, "xB", "is present", null);
+ CEGNode node10 = createNode(model, "yB", "is present", null);
+ CEGNode node6 = createNode(model, "effekt", "is present", null);
+ CEGNode node11 = createNode(model, "Intermediate Node2", "is present", NodeType.OR);
+
+ createConnection(model, node2, node7, false);
+ createConnection(model, node3, node7, false);
+ createConnection(model, node4, node7, false);
+ createConnection(model, node5, node1, false);
+ createConnection(model, node7, node1, false);
+ createConnection(model, node1, node8, false);
+ createConnection(model, node9, node11, false);
+ createConnection(model, node10, node11, false);
+ createConnection(model, node11, node8, false);
+ createConnection(model, node8, node6, false);
+ JSONArray generated = generateCEGWithModelRequirementsText(text);
+ checkResultingModel(generated, model);
+ }
+
+ @Test
+ public void testModelGenerationPseudoCodeWithMultipleNesting() {
+ String text = "WENN x UND y DANN WENN xB ODER yB DANN WENN xC UND yC DANN effekt ENDE-WENN ENDE-WENN ENDE-WENN";
+ RequirementsFactory f = RequirementsFactory.eINSTANCE;
+ CEGModel model = f.createCEGModel();
+ CEGNode node1 = createNode(model, "BR1", "is present", NodeType.AND);
+ CEGNode node2 = createNode(model, "x", "is present", null);
+ CEGNode node3 = createNode(model, "y", "is present", null);
+
+ CEGNode node4 = createNode(model, "BR2", "is present", NodeType.AND);
+ CEGNode node5 = createNode(model, "xB", "is present", null);
+ CEGNode node6 = createNode(model, "yB", "is present", null);
+ CEGNode node7 = createNode(model, "Intermediate Node1", "is present", NodeType.OR);
+
+ CEGNode node8 = createNode(model, "BR3", "is present", NodeType.AND);
+ CEGNode node9 = createNode(model, "xC", "is present", null);
+ CEGNode node10 = createNode(model, "yC", "is present", null);
+ CEGNode node11 = createNode(model, "effekt", "is present", null);
+
+ createConnection(model, node2, node1, false);
+ createConnection(model, node3, node1, false);
+ createConnection(model, node1, node4, false);
+ createConnection(model, node5, node7, false);
+ createConnection(model, node6, node7, false);
+ createConnection(model, node7, node4, false);
+ createConnection(model, node4, node8, false);
+ createConnection(model, node9, node8, false);
+ createConnection(model, node10, node8, false);
+ createConnection(model, node8, node11, false);
+ JSONArray generated = generateCEGWithModelRequirementsText(text);
+ checkResultingModel(generated, model);
}
+ @Test
+ public void testModelGenerationPseudoCodeWithMultipleNestingAndAlternativeEffect() {
+ String text = "WENN x UND y DANN WENN xB ODER yB DANN WENN xC UND yC DANN effekt SONST aEffekt ENDE-WENN ENDE-WENN ENDE-WENN";
+ RequirementsFactory f = RequirementsFactory.eINSTANCE;
+ CEGModel model = f.createCEGModel();
+ CEGNode node1 = createNode(model, "BR1", "is present", NodeType.AND);
+ CEGNode node2 = createNode(model, "x", "is present", null);
+ CEGNode node3 = createNode(model, "y", "is present", null);
+
+ CEGNode node4 = createNode(model, "BR2", "is present", NodeType.AND);
+ CEGNode node5 = createNode(model, "xB", "is present", null);
+ CEGNode node6 = createNode(model, "yB", "is present", null);
+ CEGNode node7 = createNode(model, "Intermediate Node1", "is present", NodeType.OR);
+
+ CEGNode node8 = createNode(model, "BR3", "is present", NodeType.AND);
+ CEGNode node9 = createNode(model, "xC", "is present", null);
+ CEGNode node10 = createNode(model, "yC", "is present", null);
+ CEGNode node11 = createNode(model, "effekt", "is present", null);
+ CEGNode node12 = createNode(model, "aEffekt", "is present", null);
+
+ createConnection(model, node2, node1, false);
+ createConnection(model, node3, node1, false);
+ createConnection(model, node1, node4, false);
+ createConnection(model, node5, node7, false);
+ createConnection(model, node6, node7, false);
+ createConnection(model, node7, node4, false);
+ createConnection(model, node4, node8, false);
+ createConnection(model, node9, node8, false);
+ createConnection(model, node10, node8, false);
+ createConnection(model, node8, node11, false);
+ createConnection(model, node8, node12, true);
+ JSONArray generated = generateCEGWithModelRequirementsText(text);
+ checkResultingModel(generated, model);
+ }
+
private List loadRules(String mainFile) throws URISyntaxException, XTextException {
URI main = getLocalFile(mainFile);
return new BusinessRuleUtil().loadXTextResources(main);
}
-
+
private URI getLocalFile(String fileName) throws URISyntaxException {
Bundle bundle = FrameworkUtil.getBundle(NLPServiceTest.class);
return URI.createURI(bundle.getResource(fileName).toURI().toString());
diff --git a/bundles/specmate-model-generation/bnd.bnd b/bundles/specmate-model-generation/bnd.bnd
index 12df0f4a1..05bdfae5d 100644
--- a/bundles/specmate-model-generation/bnd.bnd
+++ b/bundles/specmate-model-generation/bnd.bnd
@@ -20,7 +20,8 @@
specmate-metrics;version=latest,\
specmate-cause-effect-patterns,\
specmate-config-api;version=latest,\
- specmate-xtext;version=latest
+ specmate-xtext;version=latest,\
+ specmate-objectif
Private-Package: \
com.specmate.modelgeneration,\
com.specmate.modelgeneration.legacy
diff --git a/bundles/specmate-model-generation/generated/buildfiles b/bundles/specmate-model-generation/generated/buildfiles
new file mode 100644
index 000000000..d354c9596
--- /dev/null
+++ b/bundles/specmate-model-generation/generated/buildfiles
@@ -0,0 +1 @@
+A:/specmate/bundles/specmate-model-generation/generated/specmate-model-generation.jar
diff --git a/bundles/specmate-model-generation/src/com/specmate/modelgeneration/GenerateModelFromPseudoCode.java b/bundles/specmate-model-generation/src/com/specmate/modelgeneration/GenerateModelFromPseudoCode.java
new file mode 100644
index 000000000..cf0108888
--- /dev/null
+++ b/bundles/specmate-model-generation/src/com/specmate/modelgeneration/GenerateModelFromPseudoCode.java
@@ -0,0 +1,378 @@
+package com.specmate.modelgeneration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.specmate.common.exception.SpecmateException;
+import com.specmate.common.exception.SpecmateInternalException;
+import com.specmate.model.administration.ErrorCode;
+import com.specmate.model.requirements.CEGModel;
+import com.specmate.model.requirements.CEGNode;
+import com.specmate.model.requirements.NodeType;
+import com.specmate.objectif.resolve.BusinessRuleUtil;
+import com.specmate.objectif.resolve.rule.AndNode;
+import com.specmate.objectif.resolve.rule.BusinessRuleNode;
+import com.specmate.objectif.resolve.rule.LiteralNode;
+import com.specmate.objectif.resolve.rule.ObjectifNode;
+import com.specmate.objectif.resolve.rule.OrNode;
+import com.specmate.xtext.XTextException;
+
+// This class transforms pseudo code into a CEG.
+// The pseudo code must conform with the implemented XText grammar.
+public class GenerateModelFromPseudoCode implements ICEGFromRequirementGenerator {
+
+ // Our factory to create the elements of the CEG (nodes and connections).
+ CEGCreation creation = new CEGCreation();
+
+ // Counter for numbering of intermediate nodes as well as business rule nodes.
+ int intermediatenum = 1;
+ int brnum = 1;
+
+ @Override
+ public CEGModel createModel(CEGModel model, String text) throws SpecmateException {
+ List rules;
+ // First, we need to load all pseudo code lines from a document / input.
+ try {
+ rules = new BusinessRuleUtil().parseXTextResource(text);
+ } catch (XTextException e) {
+ throw new SpecmateInternalException(ErrorCode.INTERNAL_PROBLEM,
+ "Unfortunately, the XText parsing of your inserted pseudo code went wrong." + e.getMessage());
+ }
+
+ BusinessRuleNode rule = rules.get(0);
+ return createCEGModelForEachSection(rule, model, null, false);
+ }
+
+ // This method creates a CEG model for each "WENN" --> "DANN" --> "ENDE-WENN"
+ // clause.
+ private CEGModel createCEGModelForEachSection(BusinessRuleNode rule, CEGModel model, CEGNode brNode,
+ boolean nesting) {
+
+ // The type of a BR node should be always "OR". Exception: The model consists
+ // only of conjunctive causes.
+ CEGNode cegNodeBR;
+
+ // If the brNode is null, we start with a new model.
+ if (brNode == null) {
+ cegNodeBR = creation.createNode(model, "BR" + (brnum++), "is present", 0, 0, NodeType.OR);
+ } else {
+ // Otherwise, we are within a recursive loop (i.e. the clause is nested) and the
+ // brNode is our superior
+ // business rule.
+ cegNodeBR = brNode;
+ }
+
+ // Check for nesting:
+ // The rootEffect contains all effects of a rule. If the rootEffect is a
+ // "BusinessRuleNode", the rule is nested and consists of multiple rules.
+ // Here we check if we need to do a recursion again or if we reached the
+ // business rule at the lowest depth (i.e. the business rule which does not
+ // contains another one).
+ ObjectifNode rootEffect = rule.getEffect();
+ if (rootEffect instanceof BusinessRuleNode) {
+ // Case: nested
+ // Basic idea: Split the whole tree in subtrees (i.e. split the tree into
+ // individual business rules) and connect first the causes to these business
+ // rules and then simply connect superior rules to inferior rules.
+ CEGNode cegNodeBRNested = creation.createNode(model, "BR" + (brnum++), "is present", 0, 0, NodeType.AND);
+ List> andCausesGroups = new ArrayList>();
+ List singleOrCauses = new ArrayList();
+
+ ObjectifNode rootCause = rule.getCause();
+ identifyCauses(rootCause, singleOrCauses, andCausesGroups);
+
+ // superior rule
+ if (nesting == false) {
+ connectCausesToBR(cegNodeBR, singleOrCauses, andCausesGroups, model);
+ } else {
+ // inferior rule
+ connectCausesToNestedBR(cegNodeBR, singleOrCauses, andCausesGroups, model);
+ }
+
+ // We do not need to identify the effects of the business rule since we know
+ // that the rule contains another one and is therefore a condition for the
+ // nested rule. We simply connect the rule with the inferior rule.
+ creation.createConnection(model, cegNodeBR, cegNodeBRNested, false);
+
+ // Start with the recursion. We update the root and do the whole procedure for
+ // the inferior rule again. Until we reach a rule which is not nested anymore.
+ createCEGModelForEachSection((BusinessRuleNode) rootEffect, model, cegNodeBRNested, true);
+
+ } else {
+ // Case: not nested
+ // RootCause contains all causes of a rule.
+ ObjectifNode rootCause = rule.getCause();
+ List effects = new ArrayList();
+ List alternativeEffects = new ArrayList();
+
+ identifyEffects(rootEffect, effects);
+
+ if (rule.hasAlternative()) {
+ rootEffect = rule.getAlternative();
+ identifyEffects(rootEffect, alternativeEffects);
+ }
+
+ // 1. Case = The rule contains only one cause. This is the case if the rootCause
+ // is a "LiteralNode".
+ if (rootCause instanceof LiteralNode) {
+ // Create a node with the content of the rootCause and connect the node with the
+ // rule node by means of identity connection.
+ CEGNode cegNode = creation.createNode(model, ((LiteralNode) rootCause).getContent(), "is present", 0, 0,
+ null);
+
+ creation.createConnection(model, cegNode, cegNodeBR, false);
+ // Search for effects of the rule.
+ //identifyEffects(rootEffect, effects);
+
+// if (rule.hasAlternative()) {
+// rootEffect = rule.getAlternative();
+// identifyEffects(rootEffect, alternativeEffects);
+// }
+
+ // Connect the rule node with all identified effects.
+ for (ObjectifNode effect : effects) {
+ CEGNode cegNodeEffect = creation.createNode(model, ((LiteralNode) effect).getContent(),
+ "is present", 0, 0, null);
+ creation.createConnection(model, cegNodeBR, cegNodeEffect, false);
+ }
+
+ // Connect the rule node with its alternative effects
+ for (ObjectifNode effect : alternativeEffects) {
+ CEGNode cegNodeEffect = creation.createNode(model, ((LiteralNode) effect).getContent(),
+ "is present", 0, 0, null);
+ creation.createConnection(model, cegNodeBR, cegNodeEffect, true);
+ }
+ } else {
+
+ // 2. Case = The rule contains multiple causes which are interconnected
+ // (conjunctions or disjunctions).
+ List> andCausesGroups = new ArrayList>();
+ List singleOrCauses = new ArrayList();
+
+ identifyCauses(rootCause, singleOrCauses, andCausesGroups);
+ //identifyEffects(rootEffect, effects);
+
+ if (nesting == false) {
+ connectCausesToBR(cegNodeBR, singleOrCauses, andCausesGroups, model);
+ } else {
+ connectCausesToNestedBR(cegNodeBR, singleOrCauses, andCausesGroups, model);
+ }
+ connectBRToEffects(cegNodeBR, effects, alternativeEffects, model);
+ }
+ }
+ return model;
+ }
+
+ private void connectBRToEffects(CEGNode cegNodeBR, List effects,
+ List alternativeEffects, CEGModel model) {
+ // Iterate over all effects and connect the business rule node with these
+ // effects.
+ for (ObjectifNode effect : effects) {
+ CEGNode cegNode = creation.createNode(model, ((LiteralNode) effect).getContent(), "is present", 0, 0, null);
+ creation.createConnection(model, cegNodeBR, cegNode, false);
+ }
+ for (ObjectifNode effect : alternativeEffects) {
+ CEGNode cegNode = creation.createNode(model, ((LiteralNode) effect).getContent(), "is present", 0, 0, null);
+ creation.createConnection(model, cegNodeBR, cegNode, true);
+ }
+ }
+
+ // Implementation for non nested BRs
+ private void connectCausesToBR(CEGNode cegNodeBR, List singleOrCauses,
+ List> andCausesGroups, CEGModel model) {
+
+ for (List andCauses : andCausesGroups) {
+
+ CEGNode intermediateNode = null;
+
+ if (andCausesGroups.size() > 0 && singleOrCauses.size() != 0) {
+ intermediateNode = creation.createNode(model, "Intermediate Node" + (intermediatenum++), "is present",
+ 0, 0, NodeType.AND);
+
+ creation.createConnection(model, intermediateNode, cegNodeBR, false);
+ }
+
+ for (ObjectifNode cause : andCauses) {
+ CEGNode cegNode = creation.createNode(model, ((LiteralNode) cause).getContent(), "is present", 0, 0,
+ null);
+
+ // There are two cases:
+ // a) there is only one set of conjunctive causes and no single / disjunctive
+ // causes --> just connect the causes with the rule without intermediate node.
+ if (andCausesGroups.size() == 1 && singleOrCauses.size() == 0) {
+ creation.createConnection(model, cegNode, cegNodeBR, false);
+ cegNodeBR.setType(NodeType.AND);
+ } else {
+ // b) otherwise we need an intermediate node and connect conjunctive causes to
+ // these nodes. All related causes share the same intermediate node!
+ creation.createConnection(model, cegNode, intermediateNode, false);
+ }
+ }
+ }
+ // We iterate over all single causes and connect them with the BR by means of a
+ // disjunction.
+ for (ObjectifNode cause : singleOrCauses) {
+ CEGNode cegNode = creation.createNode(model, ((LiteralNode) cause).getContent(), "is present", 0, 0, null);
+ creation.createConnection(model, cegNode, cegNodeBR, false);
+ }
+ }
+
+ // Implementation for nested BRs:
+ // It is important to differentiate between non nested and nested BR since
+ // nested BRs have always the NodeType "AND" (because superior BRs are always a
+ // condition for the nested ones). As a result, here we need intermediate nodes
+ // for the disjunctive causes and no intermediate nodes for the conjunction
+ // since they can be directly connected to the BR.
+ private void connectCausesToNestedBR(CEGNode cegNodeBR, List singleOrCauses,
+ List> andCausesGroups, CEGModel model) {
+
+ CEGNode intermediateNodeNested = null;
+
+ if (singleOrCauses.size() > 1) {
+ intermediateNodeNested = creation.createNode(model, "Intermediate Node" + (intermediatenum++), "is present",
+ 0, 0, NodeType.OR);
+ creation.createConnection(model, intermediateNodeNested, cegNodeBR, false);
+ }
+
+ for (List andCauses : andCausesGroups) {
+
+ CEGNode intermediateNode = null;
+
+ if (andCausesGroups.size() > 0 && singleOrCauses.size() != 0) {
+ intermediateNode = creation.createNode(model, "Intermediate Node" + (intermediatenum++), "is present",
+ 0, 0, NodeType.AND);
+ creation.createConnection(model, intermediateNode, intermediateNodeNested, false);
+ }
+
+ for (ObjectifNode cause : andCauses) {
+ CEGNode cegNode = creation.createNode(model, ((LiteralNode) cause).getContent(), "is present", 0, 0,
+ null);
+
+ if (singleOrCauses.size() == 1 || andCausesGroups.size() == 1 && singleOrCauses.size() == 0) {
+ creation.createConnection(model, cegNode, cegNodeBR, false);
+ } else {
+ creation.createConnection(model, cegNode, intermediateNode, false);
+ }
+ }
+ }
+
+ for (ObjectifNode cause : singleOrCauses) {
+ CEGNode cegNode = creation.createNode(model, ((LiteralNode) cause).getContent(), "is present", 0, 0, null);
+ if (singleOrCauses.size() == 1) {
+ creation.createConnection(model, cegNode, cegNodeBR, false);
+ } else {
+ creation.createConnection(model, cegNode, intermediateNodeNested, false);
+ }
+ }
+ }
+
+ private void identifyEffects(ObjectifNode rootEffect, List effects) {
+ // 1. Case: There is only a single effect
+ if (rootEffect instanceof LiteralNode) {
+ effects.add(rootEffect);
+ }
+
+ // 2. Case: The effects are interconnected.
+ if (rootEffect instanceof AndNode) {
+
+ if (rootEffect.getLeft() instanceof LiteralNode) {
+ effects.add(rootEffect.getLeft());
+ }
+
+ if (rootEffect.getRight() instanceof LiteralNode) {
+ effects.add(rootEffect.getRight());
+ }
+
+ if (rootEffect.getLeft() instanceof AndNode) {
+ connectAndCauses(rootEffect.getLeft(), effects);
+ }
+
+ if (rootEffect.getRight() instanceof AndNode) {
+ connectAndCauses(rootEffect.getRight(), effects);
+ }
+ }
+ }
+
+ // Here we connect causes which are interconnected using conjunctions.
+ // Related causes are saved within individual lists.
+ private void connectAndCauses(ObjectifNode rootCause, List andCauses) {
+ if (rootCause instanceof AndNode) {
+
+ if (rootCause.getLeft() instanceof LiteralNode) {
+ // add cause to the list.
+ andCauses.add(rootCause.getLeft());
+ }
+
+ if (rootCause.getRight() instanceof LiteralNode) {
+ // add cause to the list.
+ andCauses.add(rootCause.getRight());
+ }
+
+ if (rootCause.getLeft() instanceof AndNode) {
+ // recursive call of the method but with updated rootcause.
+ // Here we do not (!) create a new list because this is connection of multiple
+ // conjunctions. So we build a large list of multiple interconnected causes.
+ connectAndCauses(rootCause.getLeft(), andCauses);
+ }
+
+ if (rootCause.getRight() instanceof AndNode) {
+ // recursive call of the method but with updated rootcause.
+ // See explanation above.
+ connectAndCauses(rootCause.getRight(), andCauses);
+ }
+ }
+ }
+
+ // Here we separate between isolated causes (disjunctive causes) and related
+ // causes (conjunctive causes).
+ private void identifyCauses(ObjectifNode rootCause, List orCauses,
+ List> causesGroups) {
+ if (rootCause instanceof OrNode) {
+ // 1. Case: A single "or" connection
+ if (rootCause.getLeft() instanceof LiteralNode) {
+ orCauses.add(rootCause.getLeft());
+ }
+
+ // belongs to case 1
+ if (rootCause.getRight() instanceof LiteralNode) {
+ orCauses.add(rootCause.getRight());
+ }
+
+ if (rootCause.getLeft() instanceof AndNode) {
+ // Here we identify a conjunction. We create a list of Objectif nodes for each
+ // identified conjunction.
+ List andCauses = new ArrayList();
+ connectAndCauses(rootCause.getLeft(), andCauses);
+ causesGroups.add(andCauses);
+ }
+
+ if (rootCause.getRight() instanceof AndNode) {
+ // Here we identify also a conjunction. Same procedure as described above.
+ List andCauses = new ArrayList();
+ connectAndCauses(rootCause.getRight(), andCauses);
+ causesGroups.add(andCauses);
+ }
+
+ if (rootCause.getRight() instanceof OrNode) {
+ // recursive call of the method with updated rootCause
+ identifyCauses(rootCause.getRight(), orCauses, causesGroups);
+ }
+
+ if (rootCause.getLeft() instanceof OrNode) {
+ // same here
+ identifyCauses(rootCause.getLeft(), orCauses, causesGroups);
+ }
+
+ } else if (rootCause instanceof AndNode) {
+ // Exceptional case if rootCause is a "AndNode".
+ // Here we also need to create a new list of conjunctive nodes.
+ List andCauses = new ArrayList();
+ connectAndCauses(rootCause, andCauses);
+ causesGroups.add(andCauses);
+
+ } else if (rootCause instanceof LiteralNode) {
+ // This is the case if the rule consists of only one cause.
+ orCauses.add(rootCause);
+ }
+ }
+}
diff --git a/bundles/specmate-model-generation/src/com/specmate/modelgeneration/GenerateModelFromRequirementService.java b/bundles/specmate-model-generation/src/com/specmate/modelgeneration/GenerateModelFromRequirementService.java
index 2531babb9..0b5fb75be 100644
--- a/bundles/specmate-model-generation/src/com/specmate/modelgeneration/GenerateModelFromRequirementService.java
+++ b/bundles/specmate-model-generation/src/com/specmate/modelgeneration/GenerateModelFromRequirementService.java
@@ -89,7 +89,13 @@ private CEGModel generateModelFromDescription(CEGModel model) throws SpecmateExc
ELanguage lang = NLPUtil.detectLanguage(text);
ICEGFromRequirementGenerator generator;
- generator = new PatternbasedCEGGenerator(lang, tagger, this.configService);
+
+ if(lang == ELanguage.PSEUDO) {
+ generator = new GenerateModelFromPseudoCode();
+ } else {
+ generator = new PatternbasedCEGGenerator(lang, tagger, this.configService);
+ }
+
try {
generator.createModel(model, text);
diff --git a/bundles/specmate-model-generators-typescript/bin/.gitignore b/bundles/specmate-model-generators-typescript/bin/.gitignore
deleted file mode 100644
index c2d9872a1..000000000
--- a/bundles/specmate-model-generators-typescript/bin/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/com/
diff --git a/bundles/specmate-model-generators-typescript/bin/com/specmate/model/generators/typescript/generateAngular.mtl b/bundles/specmate-model-generators-typescript/bin/com/specmate/model/generators/typescript/generateAngular.mtl
new file mode 100644
index 000000000..7a6cbc508
--- /dev/null
+++ b/bundles/specmate-model-generators-typescript/bin/com/specmate/model/generators/typescript/generateAngular.mtl
@@ -0,0 +1,144 @@
+[comment encoding = UTF-8 /]
+[module generateAngular('http://www.eclipse.org/emf/2002/Ecore')]
+
+[template public generateElement(aClass : EClass)]
+[comment @main/]
+
+[file (aClass.name.concat('.ts'), false)]
+ import './support/gentypes';
+ import { Proxy } from './support/proxy';
+
+ [comment imports for referenced classes /]
+ [if ((aClass.ePackage.name='history') or (aClass.ePackage.name='batch'))]
+ [for (r: EString | aClass.eAllReferences.eType.name->asSet())]
+ import { [r /] } from './[r/]';
+ [/for]
+ [/if]
+
+ [if (aClass.interface)]
+ export interface [aClass.name.toUpperFirst()/] {
+ [else]
+ export class [aClass.name.toUpperFirst()/] {
+ [/if]
+
+ ___nsuri: string[if not (aClass.interface)] = "[aClass.ePackage.nsURI /]"[/if];
+ [if not (aClass.interface)]public[/if] url: string;
+ [if not (aClass.interface)]public[/if] className: string[if not (aClass.interface)] = "[aClass.name.toUpperFirst()/]"[/if];
+ [if not (aClass.interface)]public static className: string = "[aClass.name.toUpperFirst()/]";[/if]
+
+ // Attributes
+ [for (a: EAttribute | aClass.eAllAttributes)]
+ [if not (aClass.interface)]public[/if] [a.name/]: [a.eType.name/][if (a.many)]['['/][']'/][/if];
+ [/for]
+
+ // References
+ [for (r: EReference | aClass.eAllReferences)]
+ [if not (r.containment)][if (not (aClass.interface))]public[/if] [r.name/]: Proxy[if (r.many)]['['/][']'/][/if];[/if]
+ [/for]
+
+ // Containment
+ [comment Containment for history package /]
+ [if ((aClass.ePackage.name='history') or (aClass.ePackage.name='batch'))]
+ [for (r: EReference | aClass.eAllReferences)]
+ [if (r.containment)][if (not (aClass.interface))]public[/if] [r.name/]: [r.eType.name/][if (r.many)]['['/][']'/][/if];[/if]
+ [/for]
+ [/if]
+
+ [comment Fetch icon string from model annotation /]
+ [if (aClass.eAnnotations.details->exists(entry|entry.key='icon'))]
+ // Icon
+ public iconClass:string = "[aClass.getEAnnotation('http://specmate.com/gen').details
+ ->select(entry|entry.key='icon')->first().value/]";
+ [/if]
+
+ }
+
+ [/file]
+[/template]
+
+[template public generateEnum(aEnum: EEnum)]
+[comment @main/]
+[file (aEnum.name.concat('.ts'), false)]
+export enum [aEnum.name/] {
+ [for (el: EEnumLiteral | aEnum.eLiterals) separator(',\n')][el.literal.toUpperCase()/] = [el.value/][/for]
+}
+[/file]
+[/template]
+
+[template public generateMeta(aPackage: EPackage)]
+[comment @main/]
+[if (aPackage.name.equalsIgnoreCase('model'))]
+ [file ('meta/field-meta.ts', false)]
+
+export class FieldMetaItem {
+ public name: string;
+ public shortDesc: string;
+ public longDesc: string;
+ public type: string;
+ public required?: boolean;
+ public values?: string;
+ public rows?: string;
+ public position?: string;
+ public allowedPattern?: string;
+}
+
+export class MetaInfo {
+ [for (aClass: EClass | aPackage.eSubpackages.eClassifiers->filter(EClass))]
+ public static [aClass.name/]: FieldMetaItem['['/][']'/] = ['['/]
+ [for (attribute: EAttribute |
+ aClass.eAllAttributes->select(attr: EAttribute | not attr.eAnnotations.getEAnnotation('http://specmate.com/form_meta')->isEmpty() and
+ aClass.eAnnotations.details->select(detail: EStringToStringMapEntry | detail.key.startsWith('disabled') and detail.value.equalsIgnoreCase(attr.name))->isEmpty())
+ ) separator(',')]
+ {
+ name: "[attribute.name/]",
+ [for (detail: EStringToStringMapEntry | attribute.eAnnotations.details) separator(',\n')]
+ [detail.key/]: [if (not (detail.value.equalsIgnoreCase('true') or detail.value.equalsIgnoreCase('false')))]'[/if][detail.value.replaceAll('\'', '\\\\' + '\'')/][if (not (detail.value.equalsIgnoreCase('true') or detail.value.equalsIgnoreCase('false')))]'[/if][/for]
+
+ }[/for]
+ [']'/];
+ [/for]
+}
+
+ [/file]
+[/if]
+[/template]
+
+[template public generateGentypes(aPackage: EPackage)]
+[comment @main/]
+
+ [if (aPackage.eContainer() = null)]
+ [file ('support/gentypes.ts', false)]
+type EInt = number;
+type EDouble = number;
+type EString = string;
+type EBoolean = boolean;
+type NodeType = string;
+type OperationType = string;
+type EDate = Date;
+type ParameterType = string;
+type AccessRights = string;
+type ErrorCode = string;
+type ELong = number;
+ [/file]
+
+ [file ('support/proxy.ts',false)]
+ export class Proxy {
+ public ___proxy = true;
+ public url:string;
+ }
+ [/file]
+ [/if]
+
+[/template]
+
+
+[query public default(type: String) : String =
+ if type='EString' then '""'
+ else if type='EInt' then 'Number(0)'
+ else if type='EBoolean' then 'false'
+ else 'undefined'
+ endif
+ endif
+ endif
+/]
+
diff --git a/bundles/specmate-nlp/src/com/specmate/nlp/api/ELanguage.java b/bundles/specmate-nlp/src/com/specmate/nlp/api/ELanguage.java
index 54ee5761c..35f5be429 100644
--- a/bundles/specmate-nlp/src/com/specmate/nlp/api/ELanguage.java
+++ b/bundles/specmate-nlp/src/com/specmate/nlp/api/ELanguage.java
@@ -1,7 +1,7 @@
package com.specmate.nlp.api;
public enum ELanguage {
- DE("de", "SUBJ"), EN("en", "subj");
+ DE("de", "SUBJ"), EN("en", "subj"), PSEUDO("pseudo", "subj");
private String language;
private String subjectDependencyType;
diff --git a/bundles/specmate-nlp/src/com/specmate/nlp/util/NLPUtil.java b/bundles/specmate-nlp/src/com/specmate/nlp/util/NLPUtil.java
index 6e97be35c..d2b444a45 100644
--- a/bundles/specmate-nlp/src/com/specmate/nlp/util/NLPUtil.java
+++ b/bundles/specmate-nlp/src/com/specmate/nlp/util/NLPUtil.java
@@ -7,6 +7,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -242,9 +243,14 @@ public static List findDependencies(Collection dependenc
private static String DE_Pattern = "\\b(der|die|das|ein|eine|einen)\\b";
public static ELanguage detectLanguage(String text) {
+ Pattern pattern= Pattern.compile(".*WENN.*ENDE-WENN.*", Pattern.DOTALL);
+
+ if (pattern.matcher(text).matches()) {
+ return ELanguage.PSEUDO;
+ }
if (text.matches("(?i)(.*)"+DE_Pattern+"(.*)")) {
return ELanguage.DE;
- }
+ }
return ELanguage.EN;
}
diff --git a/bundles/specmate-objectif/src/com/specmate/objectif/resolve/rule/ObjectifNode.java b/bundles/specmate-objectif/src/com/specmate/objectif/resolve/rule/ObjectifNode.java
index dbe8ae26a..75ebe3004 100644
--- a/bundles/specmate-objectif/src/com/specmate/objectif/resolve/rule/ObjectifNode.java
+++ b/bundles/specmate-objectif/src/com/specmate/objectif/resolve/rule/ObjectifNode.java
@@ -2,4 +2,11 @@
public abstract class ObjectifNode {
abstract void generateCEG();
+ public ObjectifNode getLeft() {
+ return null;
+ }
+
+ public ObjectifNode getRight() {
+ return null;
+ }
}
diff --git a/bundles/specmate-std-env/dev-specmate-all.bndrun b/bundles/specmate-std-env/dev-specmate-all.bndrun
index 9c67c2c15..75688de9e 100644
--- a/bundles/specmate-std-env/dev-specmate-all.bndrun
+++ b/bundles/specmate-std-env/dev-specmate-all.bndrun
@@ -1,4 +1,4 @@
--runfw: org.eclipse.osgi;version='[3.13.300.v20190218-1622,3.13.300.v20190218-1622]'
+-runfw: org.eclipse.osgi;version='[3.13.300.v20190218-1622,3.13.300.v20190218-1622]'
-runrequires: \
osgi.identity;filter:='(osgi.identity=specmate-cdo-server)',\
osgi.identity;filter:='(osgi.identity=org.apache.felix.gogo.command)',\
@@ -47,7 +47,8 @@
osgi.identity;filter:='(osgi.identity=specmate-jira-connector)',\
osgi.identity;filter:='(osgi.identity=specmate-nlp)',\
osgi.identity;filter:='(osgi.identity=specmate-model-generation)',\
- bnd.identity;id='log4j'
+ bnd.identity;id='log4j',\
+ bnd.identity;id='specmate-objectif'
-runbundles: \
javassist;version='[3.18.1,3.18.2)',\
javax.annotation-api;version='[1.2.0,1.2.1)',\
@@ -222,19 +223,21 @@
org.eclipse.xtext.xbase.lib;version='[2.10.0,2.10.1)',\
specmate-cause-effect-patterns;version=snapshot,\
specmate-xtext;version=snapshot,\
- jaxb-api;version='[2.3.1,2.3.2)'
-
--runproperties: \
- jetty.http.port=8080,\
- jetty.etc.config.urls='etc/jetty.xml,etc/jetty-http.xml,etc/jetty-deployer.xml,etc/jetty-rewrite.xml',\
- osgi.console=,\
- jetty.home.bundle=specmate-jettystarter,\
- osgi.compatibility.bootdelegation=true,\
- equinox.log.history.max=1000,\
- org.osgi.service.log.admin.loglevel=DEBUG
--runrepos: \
- Workspace,\
- Local
--runvm: -Xmx6000m\n\
- -Djdk.crypto.KeyAgreement.legacyKDF=true
--resolve: auto
\ No newline at end of file
+ jaxb-api;version='[2.3.0,2.3.1)',\
+ specmate-objectif;version=snapshot
+
+-runproperties: \
+ jetty.http.port=8080,\
+ jetty.etc.config.urls='etc/jetty.xml,etc/jetty-http.xml,etc/jetty-deployer.xml,etc/jetty-rewrite.xml',\
+ osgi.console=,\
+ jetty.home.bundle=specmate-jettystarter,\
+ osgi.compatibility.bootdelegation=true,\
+ equinox.log.history.max=1000,\
+ org.osgi.service.log.admin.loglevel=DEBUG
+-runrepos: \
+ Workspace,\
+ Local
+-runvm: -Xmx6000m\n\
+ -Djdk.crypto.KeyAgreement.legacyKDF=true
+-resolve: auto
+-runee: JavaSE-11
\ No newline at end of file