aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/language-web/src
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-11-03 19:12:08 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-11-03 19:12:19 +0100
commit32d469d0284d1ab1540423e705a5d3c8e7d99705 (patch)
treedcff140c1af411612c2ca61a34471134d762843a /subprojects/language-web/src
parentrefactor(langauge-web): use generator facades (diff)
downloadrefinery-32d469d0284d1ab1540423e705a5d3c8e7d99705.tar.gz
refinery-32d469d0284d1ab1540423e705a5d3c8e7d99705.tar.zst
refinery-32d469d0284d1ab1540423e705a5d3c8e7d99705.zip
refactor: smenatics and facades
Also moves model metadata into language-web, since we only use it on the frontent.
Diffstat (limited to 'subprojects/language-web/src')
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationSuccessResult.java4
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java30
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/PartialInterpretation2Json.java21
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsSuccessResult.java4
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java30
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/BuiltInDetail.java10
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/ClassDetail.java16
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/Metadata.java12
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/MetadataCreator.java202
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/NodeKind.java12
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/NodeMetadata.java9
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/OppositeReferenceDetail.java9
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/PredicateDetail.java16
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/ReferenceDetail.java16
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationDetail.java10
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationMetadata.java9
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java2
17 files changed, 368 insertions, 44 deletions
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationSuccessResult.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationSuccessResult.java
index 21be4e08..0abe116e 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationSuccessResult.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationSuccessResult.java
@@ -6,8 +6,8 @@
6package tools.refinery.language.web.generator; 6package tools.refinery.language.web.generator;
7 7
8import com.google.gson.JsonObject; 8import com.google.gson.JsonObject;
9import tools.refinery.language.semantics.metadata.NodeMetadata; 9import tools.refinery.language.web.semantics.metadata.NodeMetadata;
10import tools.refinery.language.semantics.metadata.RelationMetadata; 10import tools.refinery.language.web.semantics.metadata.RelationMetadata;
11 11
12import java.util.List; 12import java.util.List;
13import java.util.UUID; 13import java.util.UUID;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java
index 7b4f957c..a3b6ca82 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/generator/ModelGenerationWorker.java
@@ -9,12 +9,14 @@ import com.google.inject.Inject;
9import org.eclipse.xtext.service.OperationCanceledManager; 9import org.eclipse.xtext.service.OperationCanceledManager;
10import org.slf4j.Logger; 10import org.slf4j.Logger;
11import org.slf4j.LoggerFactory; 11import org.slf4j.LoggerFactory;
12import tools.refinery.generator.ModelGeneratorBuilder; 12import tools.refinery.generator.ModelGenerator;
13import tools.refinery.generator.ModelGeneratorFactory;
14import tools.refinery.language.web.semantics.metadata.MetadataCreator;
15import tools.refinery.generator.ProblemLoader;
13import tools.refinery.generator.ValidationErrorsException; 16import tools.refinery.generator.ValidationErrorsException;
14import tools.refinery.language.web.semantics.PartialInterpretation2Json; 17import tools.refinery.language.web.semantics.PartialInterpretation2Json;
15import tools.refinery.language.web.xtext.server.ThreadPoolExecutorServiceProvider; 18import tools.refinery.language.web.xtext.server.ThreadPoolExecutorServiceProvider;
16import tools.refinery.language.web.xtext.server.push.PushWebDocument; 19import tools.refinery.language.web.xtext.server.push.PushWebDocument;
17import tools.refinery.store.reasoning.literal.Concreteness;
18import tools.refinery.store.util.CancellationToken; 20import tools.refinery.store.util.CancellationToken;
19 21
20import java.io.IOException; 22import java.io.IOException;
@@ -38,7 +40,13 @@ public class ModelGenerationWorker implements Runnable {
38 private OperationCanceledManager operationCanceledManager; 40 private OperationCanceledManager operationCanceledManager;
39 41
40 @Inject 42 @Inject
41 private ModelGeneratorBuilder generatorBuilder; 43 private ProblemLoader problemLoader;
44
45 @Inject
46 private ModelGeneratorFactory generatorFactory;
47
48 @Inject
49 private MetadataCreator metadataCreator;
42 50
43 @Inject 51 @Inject
44 private PartialInterpretation2Json partialInterpretation2Json; 52 private PartialInterpretation2Json partialInterpretation2Json;
@@ -127,9 +135,10 @@ public class ModelGenerationWorker implements Runnable {
127 135
128 public ModelGenerationResult doRun() throws IOException { 136 public ModelGenerationResult doRun() throws IOException {
129 cancellationToken.checkCancelled(); 137 cancellationToken.checkCancelled();
138 var problem = problemLoader.cancellationToken(cancellationToken).loadString(text);
139 ModelGenerator generator;
130 try { 140 try {
131 generatorBuilder.cancellationToken(cancellationToken); 141 generator = generatorFactory.cancellationToken(cancellationToken).createGenerator(problem);
132 generatorBuilder.fromString(text);
133 } catch (ValidationErrorsException e) { 142 } catch (ValidationErrorsException e) {
134 var errors = e.getErrors(); 143 var errors = e.getErrors();
135 if (errors != null && !errors.isEmpty()) { 144 if (errors != null && !errors.isEmpty()) {
@@ -137,20 +146,19 @@ public class ModelGenerationWorker implements Runnable {
137 } 146 }
138 throw e; 147 throw e;
139 } 148 }
140 var generator = generatorBuilder.build();
141 notifyResult(new ModelGenerationStatusResult(uuid, "Generating model")); 149 notifyResult(new ModelGenerationStatusResult(uuid, "Generating model"));
142 generator.setRandomSeed(randomSeed); 150 generator.setRandomSeed(randomSeed);
143 if (!generator.tryRun()) { 151 if (!generator.tryGenerate()) {
144 return new ModelGenerationErrorResult(uuid, "Problem is unsatisfiable"); 152 return new ModelGenerationErrorResult(uuid, "Problem is unsatisfiable");
145 } 153 }
146 notifyResult(new ModelGenerationStatusResult(uuid, "Saving generated model")); 154 notifyResult(new ModelGenerationStatusResult(uuid, "Saving generated model"));
147 cancellationToken.checkCancelled(); 155 cancellationToken.checkCancelled();
148 var nodesMetadata = generator.getNodesMetadata(); 156 metadataCreator.setProblemTrace(generator.getProblemTrace());
157 var nodesMetadata = metadataCreator.getNodesMetadata(generator.getModel(), false);
149 cancellationToken.checkCancelled(); 158 cancellationToken.checkCancelled();
150 var relationsMetadata = generator.getProblemTrace().getRelationsMetadata(); 159 var relationsMetadata = metadataCreator.getRelationsMetadata();
151 cancellationToken.checkCancelled(); 160 cancellationToken.checkCancelled();
152 var partialInterpretation = partialInterpretation2Json.getPartialInterpretation(generator, 161 var partialInterpretation = partialInterpretation2Json.getPartialInterpretation(generator, cancellationToken);
153 Concreteness.CANDIDATE, cancellationToken);
154 return new ModelGenerationSuccessResult(uuid, nodesMetadata, relationsMetadata, partialInterpretation); 162 return new ModelGenerationSuccessResult(uuid, nodesMetadata, relationsMetadata, partialInterpretation);
155 } 163 }
156 164
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/PartialInterpretation2Json.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/PartialInterpretation2Json.java
index 7afed5c0..efe04592 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/PartialInterpretation2Json.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/PartialInterpretation2Json.java
@@ -9,12 +9,10 @@ import com.google.gson.JsonArray;
9import com.google.gson.JsonObject; 9import com.google.gson.JsonObject;
10import com.google.inject.Inject; 10import com.google.inject.Inject;
11import com.google.inject.Singleton; 11import com.google.inject.Singleton;
12import tools.refinery.generator.AbstractRefinery; 12import tools.refinery.generator.ModelFacade;
13import tools.refinery.language.semantics.model.SemanticsUtils; 13import tools.refinery.language.semantics.SemanticsUtils;
14import tools.refinery.store.map.Cursor; 14import tools.refinery.store.map.Cursor;
15import tools.refinery.store.model.Model; 15import tools.refinery.store.model.Model;
16import tools.refinery.store.reasoning.ReasoningAdapter;
17import tools.refinery.store.reasoning.literal.Concreteness;
18import tools.refinery.store.reasoning.representation.PartialRelation; 16import tools.refinery.store.reasoning.representation.PartialRelation;
19import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator; 17import tools.refinery.store.reasoning.translator.multiobject.MultiObjectTranslator;
20import tools.refinery.store.tuple.Tuple; 18import tools.refinery.store.tuple.Tuple;
@@ -27,15 +25,13 @@ public class PartialInterpretation2Json {
27 @Inject 25 @Inject
28 private SemanticsUtils semanticsUtils; 26 private SemanticsUtils semanticsUtils;
29 27
30 public JsonObject getPartialInterpretation(AbstractRefinery refinery, Concreteness concreteness, 28 public JsonObject getPartialInterpretation(ModelFacade facade, CancellationToken cancellationToken) {
31 CancellationToken cancellationToken) { 29 var model = facade.getModel();
32 var model = refinery.getModel();
33 var adapter = model.getAdapter(ReasoningAdapter.class);
34 var json = new JsonObject(); 30 var json = new JsonObject();
35 for (var entry : refinery.getProblemTrace().getRelationTrace().entrySet()) { 31 for (var entry : facade.getProblemTrace().getRelationTrace().entrySet()) {
36 var relation = entry.getKey(); 32 var relation = entry.getKey();
37 var partialSymbol = entry.getValue(); 33 var partialSymbol = entry.getValue();
38 var tuples = getTuplesJson(adapter, concreteness, partialSymbol); 34 var tuples = getTuplesJson(facade, partialSymbol);
39 var name = semanticsUtils.getName(relation).orElse(partialSymbol.name()); 35 var name = semanticsUtils.getName(relation).orElse(partialSymbol.name());
40 json.add(name, tuples); 36 json.add(name, tuples);
41 cancellationToken.checkCancelled(); 37 cancellationToken.checkCancelled();
@@ -44,9 +40,8 @@ public class PartialInterpretation2Json {
44 return json; 40 return json;
45 } 41 }
46 42
47 private static JsonArray getTuplesJson(ReasoningAdapter adapter, Concreteness concreteness, 43 private static JsonArray getTuplesJson(ModelFacade facade, PartialRelation partialSymbol) {
48 PartialRelation partialSymbol) { 44 var interpretation = facade.getPartialInterpretation(partialSymbol);
49 var interpretation = adapter.getPartialInterpretation(concreteness, partialSymbol);
50 var cursor = interpretation.getAll(); 45 var cursor = interpretation.getAll();
51 return getTuplesJson(cursor); 46 return getTuplesJson(cursor);
52 } 47 }
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsSuccessResult.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsSuccessResult.java
index 350b0b2b..f26fa2b2 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsSuccessResult.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsSuccessResult.java
@@ -6,8 +6,8 @@
6package tools.refinery.language.web.semantics; 6package tools.refinery.language.web.semantics;
7 7
8import com.google.gson.JsonObject; 8import com.google.gson.JsonObject;
9import tools.refinery.language.semantics.metadata.NodeMetadata; 9import tools.refinery.language.web.semantics.metadata.NodeMetadata;
10import tools.refinery.language.semantics.metadata.RelationMetadata; 10import tools.refinery.language.web.semantics.metadata.RelationMetadata;
11 11
12import java.util.List; 12import java.util.List;
13 13
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java
index a8f16c84..44974869 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/SemanticsWorker.java
@@ -16,10 +16,10 @@ import org.eclipse.xtext.validation.IDiagnosticConverter;
16import org.eclipse.xtext.validation.Issue; 16import org.eclipse.xtext.validation.Issue;
17import org.eclipse.xtext.web.server.validation.ValidationResult; 17import org.eclipse.xtext.web.server.validation.ValidationResult;
18import tools.refinery.generator.ModelSemantics; 18import tools.refinery.generator.ModelSemantics;
19import tools.refinery.generator.ModelSemanticsBuilder; 19import tools.refinery.generator.ModelSemanticsFactory;
20import tools.refinery.language.model.problem.Problem; 20import tools.refinery.language.model.problem.Problem;
21import tools.refinery.language.semantics.model.TracedException; 21import tools.refinery.language.web.semantics.metadata.MetadataCreator;
22import tools.refinery.store.reasoning.literal.Concreteness; 22import tools.refinery.language.semantics.TracedException;
23import tools.refinery.store.reasoning.translator.TranslationException; 23import tools.refinery.store.reasoning.translator.TranslationException;
24import tools.refinery.store.util.CancellationToken; 24import tools.refinery.store.util.CancellationToken;
25 25
@@ -30,16 +30,19 @@ class SemanticsWorker implements Callable<SemanticsResult> {
30 private static final String DIAGNOSTIC_ID = "tools.refinery.language.semantics.SemanticError"; 30 private static final String DIAGNOSTIC_ID = "tools.refinery.language.semantics.SemanticError";
31 31
32 @Inject 32 @Inject
33 private PartialInterpretation2Json partialInterpretation2Json;
34
35 @Inject
36 private OperationCanceledManager operationCanceledManager; 33 private OperationCanceledManager operationCanceledManager;
37 34
38 @Inject 35 @Inject
39 private IDiagnosticConverter diagnosticConverter; 36 private IDiagnosticConverter diagnosticConverter;
40 37
41 @Inject 38 @Inject
42 private ModelSemanticsBuilder semanticsBuilder; 39 private ModelSemanticsFactory semanticsFactory;
40
41 @Inject
42 private MetadataCreator metadataCreator;
43
44 @Inject
45 private PartialInterpretation2Json partialInterpretation2Json;
43 46
44 private Problem problem; 47 private Problem problem;
45 48
@@ -56,13 +59,10 @@ class SemanticsWorker implements Callable<SemanticsResult> {
56 59
57 @Override 60 @Override
58 public SemanticsResult call() { 61 public SemanticsResult call() {
59 semanticsBuilder.cancellationToken(cancellationToken);
60 cancellationToken.checkCancelled(); 62 cancellationToken.checkCancelled();
61 ModelSemantics semantics; 63 ModelSemantics semantics;
62 try { 64 try {
63 semanticsBuilder.problem(problem); 65 semantics = semanticsFactory.cancellationToken(cancellationToken).createSemantics(problem);
64 cancellationToken.checkCancelled();
65 semantics = semanticsBuilder.build();
66 } catch (TranslationException e) { 66 } catch (TranslationException e) {
67 return new SemanticsInternalErrorResult(e.getMessage()); 67 return new SemanticsInternalErrorResult(e.getMessage());
68 } catch (TracedException e) { 68 } catch (TracedException e) {
@@ -72,12 +72,12 @@ class SemanticsWorker implements Callable<SemanticsResult> {
72 return getTracedErrorResult(e.getSourceElement(), message); 72 return getTracedErrorResult(e.getSourceElement(), message);
73 } 73 }
74 cancellationToken.checkCancelled(); 74 cancellationToken.checkCancelled();
75 var nodesMetadata = semantics.getNodesMetadata(); 75 metadataCreator.setProblemTrace(semantics.getProblemTrace());
76 var nodesMetadata = metadataCreator.getNodesMetadata(semantics.getModel(), true);
76 cancellationToken.checkCancelled(); 77 cancellationToken.checkCancelled();
77 var relationsMetadata = semantics.getProblemTrace().getRelationsMetadata(); 78 var relationsMetadata = metadataCreator.getRelationsMetadata();
78 cancellationToken.checkCancelled(); 79 cancellationToken.checkCancelled();
79 var partialInterpretation = partialInterpretation2Json.getPartialInterpretation(semantics, 80 var partialInterpretation = partialInterpretation2Json.getPartialInterpretation(semantics, cancellationToken);
80 Concreteness.PARTIAL, cancellationToken);
81 return new SemanticsSuccessResult(nodesMetadata, relationsMetadata, partialInterpretation); 81 return new SemanticsSuccessResult(nodesMetadata, relationsMetadata, partialInterpretation);
82 } 82 }
83 83
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/BuiltInDetail.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/BuiltInDetail.java
new file mode 100644
index 00000000..27eb7ad7
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/BuiltInDetail.java
@@ -0,0 +1,10 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics.metadata;
7
8public record BuiltInDetail() implements RelationDetail {
9 public static final BuiltInDetail INSTANCE = new BuiltInDetail();
10}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/ClassDetail.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/ClassDetail.java
new file mode 100644
index 00000000..42495950
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/ClassDetail.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics.metadata;
7
8public record ClassDetail(boolean abstractClass) implements RelationDetail {
9 public static final ClassDetail CONCRETE_CLASS = new ClassDetail(false);
10
11 public static final ClassDetail ABSTRACT_CLASS = new ClassDetail(true);
12
13 public static ClassDetail ofAbstractClass(boolean abstractClass) {
14 return abstractClass ? ABSTRACT_CLASS : CONCRETE_CLASS;
15 }
16}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/Metadata.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/Metadata.java
new file mode 100644
index 00000000..5e1fac05
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/Metadata.java
@@ -0,0 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics.metadata;
7
8public sealed interface Metadata permits NodeMetadata, RelationMetadata {
9 String name();
10
11 String simpleName();
12}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/MetadataCreator.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/MetadataCreator.java
new file mode 100644
index 00000000..3fbc5d2d
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/MetadataCreator.java
@@ -0,0 +1,202 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics.metadata;
7
8import com.google.inject.Inject;
9import org.eclipse.emf.ecore.EObject;
10import org.eclipse.xtext.naming.IQualifiedNameConverter;
11import org.eclipse.xtext.naming.IQualifiedNameProvider;
12import org.eclipse.xtext.naming.QualifiedName;
13import org.eclipse.xtext.scoping.IScope;
14import org.eclipse.xtext.scoping.IScopeProvider;
15import tools.refinery.language.model.problem.*;
16import tools.refinery.language.semantics.ProblemTrace;
17import tools.refinery.language.semantics.TracedException;
18import tools.refinery.language.utils.ProblemUtil;
19import tools.refinery.store.model.Model;
20import tools.refinery.store.reasoning.ReasoningAdapter;
21import tools.refinery.store.reasoning.representation.PartialRelation;
22
23import java.util.ArrayList;
24import java.util.Collections;
25import java.util.Comparator;
26import java.util.List;
27
28public class MetadataCreator {
29 @Inject
30 private IScopeProvider scopeProvider;
31
32 @Inject
33 private IQualifiedNameProvider qualifiedNameProvider;
34
35 @Inject
36 private IQualifiedNameConverter qualifiedNameConverter;
37
38 private ProblemTrace problemTrace;
39
40 private IScope nodeScope;
41
42 private IScope relationScope;
43
44 public void setProblemTrace(ProblemTrace problemTrace) {
45 if (this.problemTrace != null) {
46 throw new IllegalArgumentException("Problem trace was already set");
47 }
48 this.problemTrace = problemTrace;
49 var problem = problemTrace.getProblem();
50 nodeScope = scopeProvider.getScope(problem, ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE);
51 relationScope = scopeProvider.getScope(problem, ProblemPackage.Literals.ASSERTION__RELATION);
52 }
53
54 public static String unnamedNode(int nodeId) {
55 return "::" + nodeId;
56 }
57
58 public List<NodeMetadata> getNodesMetadata(Model model, boolean preserveNewNodes) {
59 int nodeCount = model.getAdapter(ReasoningAdapter.class).getNodeCount();
60 var nodeTrace = problemTrace.getNodeTrace();
61 var nodes = new NodeMetadata[Math.max(nodeTrace.size(), nodeCount)];
62 for (var entry : nodeTrace.keyValuesView()) {
63 var node = entry.getOne();
64 var id = entry.getTwo();
65 nodes[id] = getNodeMetadata(id, node, preserveNewNodes);
66 }
67 for (int i = 0; i < nodes.length; i++) {
68 if (nodes[i] == null) {
69 var nodeName = unnamedNode(i);
70 nodes[i] = new NodeMetadata(nodeName, nodeName, NodeKind.IMPLICIT);
71 }
72 }
73 return List.of(nodes);
74 }
75
76 private NodeMetadata getNodeMetadata(int nodeId, Node node, boolean preserveNewNodes) {
77 var kind = getNodeKind(node);
78 if (!preserveNewNodes && kind == NodeKind.NEW) {
79 var nodeName = unnamedNode(nodeId);
80 return new NodeMetadata(nodeName, nodeName, NodeKind.IMPLICIT);
81 }
82 var qualifiedName = getQualifiedName(node);
83 var simpleName = getSimpleName(node, qualifiedName, nodeScope);
84 return new NodeMetadata(qualifiedNameConverter.toString(qualifiedName),
85 qualifiedNameConverter.toString(simpleName), getNodeKind(node));
86 }
87
88 private NodeKind getNodeKind(Node node) {
89 if (ProblemUtil.isImplicitNode(node)) {
90 return NodeKind.IMPLICIT;
91 } else if (ProblemUtil.isIndividualNode(node)) {
92 return NodeKind.INDIVIDUAL;
93 } else if (ProblemUtil.isNewNode(node)) {
94 return NodeKind.NEW;
95 } else {
96 throw new TracedException(node, "Unknown node type");
97 }
98 }
99
100 public List<RelationMetadata> getRelationsMetadata() {
101 var relationTrace = problemTrace.getRelationTrace();
102 var relations = new ArrayList<RelationMetadata>(relationTrace.size());
103 for (var entry : relationTrace.entrySet()) {
104 var relation = entry.getKey();
105 var partialRelation = entry.getValue();
106 var metadata = getRelationMetadata(relation, partialRelation);
107 relations.add(metadata);
108 }
109 return Collections.unmodifiableList(relations);
110 }
111
112 private RelationMetadata getRelationMetadata(Relation relation, PartialRelation partialRelation) {
113 var qualifiedName = getQualifiedName(relation);
114 var qualifiedNameString = qualifiedNameConverter.toString(qualifiedName);
115 var simpleName = getSimpleName(relation, qualifiedName, relationScope);
116 var simpleNameString = qualifiedNameConverter.toString(simpleName);
117 var arity = partialRelation.arity();
118 var detail = getRelationDetail(relation, partialRelation);
119 return new RelationMetadata(qualifiedNameString, simpleNameString, arity, detail);
120 }
121
122 private RelationDetail getRelationDetail(Relation relation, PartialRelation partialRelation) {
123 if (ProblemUtil.isBuiltIn(relation) && !ProblemUtil.isError(relation)) {
124 return getBuiltInDetail();
125 }
126 if (relation instanceof ClassDeclaration classDeclaration) {
127 return getClassDetail(classDeclaration);
128 } else if (relation instanceof ReferenceDeclaration) {
129 return getReferenceDetail(partialRelation);
130 } else if (relation instanceof EnumDeclaration) {
131 return getEnumDetail();
132 } else if (relation instanceof PredicateDefinition predicateDefinition) {
133 return getPredicateDetail(predicateDefinition);
134 } else {
135 throw new TracedException(relation, "Unknown relation");
136 }
137 }
138
139 private RelationDetail getBuiltInDetail() {
140 return BuiltInDetail.INSTANCE;
141 }
142
143 private RelationDetail getClassDetail(ClassDeclaration classDeclaration) {
144 return ClassDetail.ofAbstractClass(classDeclaration.isAbstract());
145 }
146
147 private RelationDetail getReferenceDetail(PartialRelation partialRelation) {
148 var metamodel = problemTrace.getMetamodel();
149 var opposite = metamodel.oppositeReferences().get(partialRelation);
150 if (opposite == null) {
151 boolean isContainment = metamodel.containmentHierarchy().containsKey(partialRelation);
152 return ReferenceDetail.ofContainment(isContainment);
153 } else {
154 boolean isContainer = metamodel.containmentHierarchy().containsKey(opposite);
155 return new OppositeReferenceDetail(isContainer, opposite.name());
156 }
157 }
158
159 private RelationDetail getEnumDetail() {
160 return ClassDetail.CONCRETE_CLASS;
161 }
162
163 private RelationDetail getPredicateDetail(PredicateDefinition predicate) {
164 return PredicateDetail.ofError(predicate.isError());
165 }
166
167 private QualifiedName getQualifiedName(EObject eObject) {
168 var qualifiedName = qualifiedNameProvider.getFullyQualifiedName(eObject);
169 if (qualifiedName == null) {
170 throw new TracedException(eObject, "Unknown qualified name");
171 }
172 return qualifiedName;
173 }
174
175 private QualifiedName getSimpleName(EObject eObject, QualifiedName qualifiedName, IScope scope) {
176 var descriptions = scope.getElements(eObject);
177 var names = new ArrayList<QualifiedName>();
178 for (var description : descriptions) {
179 // {@code getQualifiedName()} will refer to the full name for objects that are loaded from the global
180 // scope, but {@code getName()} returns the qualified name that we set in
181 // {@code ProblemResourceDescriptionStrategy}.
182 names.add(description.getName());
183 }
184 names.sort(Comparator.comparingInt(QualifiedName::getSegmentCount));
185 for (var simpleName : names) {
186 if (names.contains(simpleName) && isUnique(scope, simpleName)) {
187 return simpleName;
188 }
189 }
190 throw new TracedException(eObject, "Ambiguous qualified name: " +
191 qualifiedNameConverter.toString(qualifiedName));
192 }
193
194 private boolean isUnique(IScope scope, QualifiedName name) {
195 var iterator = scope.getElements(name).iterator();
196 if (!iterator.hasNext()) {
197 return false;
198 }
199 iterator.next();
200 return !iterator.hasNext();
201 }
202}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/NodeKind.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/NodeKind.java
new file mode 100644
index 00000000..fa863bc2
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/NodeKind.java
@@ -0,0 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics.metadata;
7
8public enum NodeKind {
9 IMPLICIT,
10 INDIVIDUAL,
11 NEW
12}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/NodeMetadata.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/NodeMetadata.java
new file mode 100644
index 00000000..5da28acf
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/NodeMetadata.java
@@ -0,0 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics.metadata;
7
8public record NodeMetadata(String name, String simpleName, NodeKind kind) implements Metadata {
9}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/OppositeReferenceDetail.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/OppositeReferenceDetail.java
new file mode 100644
index 00000000..98e7fec8
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/OppositeReferenceDetail.java
@@ -0,0 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics.metadata;
7
8public record OppositeReferenceDetail(boolean container, String opposite) implements RelationDetail {
9}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/PredicateDetail.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/PredicateDetail.java
new file mode 100644
index 00000000..d4ac4b65
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/PredicateDetail.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics.metadata;
7
8public record PredicateDetail(boolean error) implements RelationDetail {
9 public static final PredicateDetail PREDICATE = new PredicateDetail(false);
10
11 public static final PredicateDetail ERROR_PREDICATE = new PredicateDetail(true);
12
13 public static PredicateDetail ofError(boolean error) {
14 return error ? ERROR_PREDICATE : PREDICATE;
15 }
16}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/ReferenceDetail.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/ReferenceDetail.java
new file mode 100644
index 00000000..42799417
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/ReferenceDetail.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics.metadata;
7
8public record ReferenceDetail(boolean containment) implements RelationDetail {
9 public static final ReferenceDetail CROSS_REFERENCE = new ReferenceDetail(false);
10
11 public static final ReferenceDetail CONTAINMENT_REFERENCE = new ReferenceDetail(true);
12
13 public static ReferenceDetail ofContainment(boolean containment) {
14 return containment ? CONTAINMENT_REFERENCE : CROSS_REFERENCE;
15 }
16}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationDetail.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationDetail.java
new file mode 100644
index 00000000..bbe563cd
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationDetail.java
@@ -0,0 +1,10 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics.metadata;
7
8public sealed interface RelationDetail permits ClassDetail, ReferenceDetail, PredicateDetail, OppositeReferenceDetail,
9 BuiltInDetail {
10}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationMetadata.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationMetadata.java
new file mode 100644
index 00000000..e5d3a091
--- /dev/null
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/semantics/metadata/RelationMetadata.java
@@ -0,0 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.language.web.semantics.metadata;
7
8public record RelationMetadata(String name, String simpleName, int arity, RelationDetail detail) implements Metadata {
9}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java
index 1fde1be5..818bd80e 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java
@@ -17,7 +17,7 @@ import org.eclipse.xtext.resource.IResourceServiceProvider;
17import org.eclipse.xtext.web.server.ISession; 17import org.eclipse.xtext.web.server.ISession;
18import org.slf4j.Logger; 18import org.slf4j.Logger;
19import org.slf4j.LoggerFactory; 19import org.slf4j.LoggerFactory;
20import tools.refinery.language.semantics.metadata.*; 20import tools.refinery.language.web.semantics.metadata.*;
21import tools.refinery.language.web.xtext.server.ResponseHandler; 21import tools.refinery.language.web.xtext.server.ResponseHandler;
22import tools.refinery.language.web.xtext.server.ResponseHandlerException; 22import tools.refinery.language.web.xtext.server.ResponseHandlerException;
23import tools.refinery.language.web.xtext.server.TransactionExecutor; 23import tools.refinery.language.web.xtext.server.TransactionExecutor;