aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel')
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ContainedTypeHierarchyBuilder.java32
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/Metamodel.java23
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java223
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelTranslator.java37
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ReferenceInfo.java13
5 files changed, 328 insertions, 0 deletions
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ContainedTypeHierarchyBuilder.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ContainedTypeHierarchyBuilder.java
new file mode 100644
index 00000000..cc43bce6
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ContainedTypeHierarchyBuilder.java
@@ -0,0 +1,32 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.metamodel;
7
8import tools.refinery.store.reasoning.representation.PartialRelation;
9import tools.refinery.store.reasoning.translator.containment.ContainmentHierarchyTranslator;
10import tools.refinery.store.reasoning.translator.typehierarchy.TypeHierarchyBuilder;
11
12import java.util.Collection;
13
14public class ContainedTypeHierarchyBuilder extends TypeHierarchyBuilder {
15 ContainedTypeHierarchyBuilder() {
16 }
17
18 boolean isInvalidType(PartialRelation type) {
19 return !typeInfoMap.containsKey(type);
20 }
21
22 void setContainedTypes(Collection<PartialRelation> containedTypes) {
23 for (var containedType : containedTypes) {
24 var currentInfo = typeInfoMap.get(containedType);
25 if (currentInfo == null) {
26 throw new IllegalArgumentException("Invalid contained type: " + containedType);
27 }
28 var newInfo = currentInfo.addSupertype(ContainmentHierarchyTranslator.CONTAINED_SYMBOL);
29 typeInfoMap.put(containedType, newInfo);
30 }
31 }
32}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/Metamodel.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/Metamodel.java
new file mode 100644
index 00000000..72b836ff
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/Metamodel.java
@@ -0,0 +1,23 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.metamodel;
7
8import tools.refinery.store.reasoning.representation.PartialRelation;
9import tools.refinery.store.reasoning.translator.containment.ContainmentInfo;
10import tools.refinery.store.reasoning.translator.crossreference.DirectedCrossReferenceInfo;
11import tools.refinery.store.reasoning.translator.crossreference.UndirectedCrossReferenceInfo;
12import tools.refinery.store.reasoning.translator.typehierarchy.TypeHierarchy;
13
14import java.util.Map;
15
16public record Metamodel(TypeHierarchy typeHierarchy, Map<PartialRelation, ContainmentInfo> containmentHierarchy,
17 Map<PartialRelation, DirectedCrossReferenceInfo> directedCrossReferences,
18 Map<PartialRelation, UndirectedCrossReferenceInfo> undirectedCrossReferences,
19 Map<PartialRelation, PartialRelation> oppositeReferences) {
20 public static MetamodelBuilder builder() {
21 return new MetamodelBuilder();
22 }
23}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java
new file mode 100644
index 00000000..92370e25
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelBuilder.java
@@ -0,0 +1,223 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.metamodel;
7
8import tools.refinery.store.reasoning.representation.PartialRelation;
9import tools.refinery.store.reasoning.translator.containment.ContainmentHierarchyTranslator;
10import tools.refinery.store.reasoning.translator.containment.ContainmentInfo;
11import tools.refinery.store.reasoning.translator.crossreference.DirectedCrossReferenceInfo;
12import tools.refinery.store.reasoning.translator.crossreference.UndirectedCrossReferenceInfo;
13import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity;
14import tools.refinery.store.reasoning.translator.multiplicity.UnconstrainedMultiplicity;
15import tools.refinery.store.reasoning.translator.typehierarchy.TypeInfo;
16import tools.refinery.store.representation.cardinality.CardinalityIntervals;
17
18import java.util.*;
19
20public class MetamodelBuilder {
21 private final ContainedTypeHierarchyBuilder typeHierarchyBuilder = new ContainedTypeHierarchyBuilder();
22 private final Map<PartialRelation, ReferenceInfo> referenceInfoMap = new LinkedHashMap<>();
23 private final Set<PartialRelation> containedTypes = new HashSet<>();
24 private final Map<PartialRelation, ContainmentInfo> containmentHierarchy = new LinkedHashMap<>();
25 private final Map<PartialRelation, DirectedCrossReferenceInfo> directedCrossReferences = new LinkedHashMap<>();
26 private final Map<PartialRelation, UndirectedCrossReferenceInfo> undirectedCrossReferences = new LinkedHashMap<>();
27 private final Map<PartialRelation, PartialRelation> oppositeReferences = new LinkedHashMap<>();
28
29 MetamodelBuilder() {
30 typeHierarchyBuilder.type(ContainmentHierarchyTranslator.CONTAINED_SYMBOL, true);
31 }
32
33 public MetamodelBuilder type(PartialRelation partialRelation, TypeInfo typeInfo) {
34 typeHierarchyBuilder.type(partialRelation, typeInfo);
35 return this;
36
37 }
38
39 public MetamodelBuilder type(PartialRelation partialRelation, boolean abstractType,
40 PartialRelation... supertypes) {
41 typeHierarchyBuilder.type(partialRelation, abstractType, supertypes);
42 return this;
43 }
44
45 public MetamodelBuilder type(PartialRelation partialRelation, boolean abstractType,
46 Collection<PartialRelation> supertypes) {
47 typeHierarchyBuilder.type(partialRelation, abstractType, supertypes);
48 return this;
49 }
50
51 public MetamodelBuilder type(PartialRelation partialRelation, PartialRelation... supertypes) {
52 typeHierarchyBuilder.type(partialRelation, supertypes);
53 return this;
54 }
55
56 public MetamodelBuilder type(PartialRelation partialRelation, Collection<PartialRelation> supertypes) {
57 typeHierarchyBuilder.type(partialRelation, supertypes);
58 return this;
59 }
60
61 public MetamodelBuilder types(Collection<Map.Entry<PartialRelation, TypeInfo>> entries) {
62 typeHierarchyBuilder.types(entries);
63 return this;
64 }
65
66 public MetamodelBuilder types(Map<PartialRelation, TypeInfo> map) {
67 typeHierarchyBuilder.types(map);
68 return this;
69 }
70
71 public MetamodelBuilder reference(PartialRelation linkType, ReferenceInfo info) {
72 if (linkType.arity() != 2) {
73 throw new IllegalArgumentException("Only references of arity 2 are supported, got %s with %d instead"
74 .formatted(linkType, linkType.arity()));
75 }
76 var putResult = referenceInfoMap.put(linkType, info);
77 if (putResult != null && !putResult.equals(info)) {
78 throw new IllegalArgumentException("Duplicate reference info for partial relation: " + linkType);
79 }
80 return this;
81 }
82
83 public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, boolean containment,
84 Multiplicity multiplicity, PartialRelation targetType,
85 PartialRelation opposite) {
86 return reference(linkType, new ReferenceInfo(containment, sourceType, multiplicity, targetType, opposite));
87 }
88
89 public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, Multiplicity multiplicity,
90 PartialRelation targetType, PartialRelation opposite) {
91 return reference(linkType, sourceType, false, multiplicity, targetType, opposite);
92 }
93
94 public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType,
95 boolean containment, PartialRelation targetType, PartialRelation opposite) {
96 return reference(linkType, sourceType, containment, UnconstrainedMultiplicity.INSTANCE, targetType, opposite);
97 }
98
99 public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, PartialRelation targetType,
100 PartialRelation opposite) {
101 return reference(linkType, sourceType, UnconstrainedMultiplicity.INSTANCE, targetType, opposite);
102 }
103
104 public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, boolean containment,
105 Multiplicity multiplicity, PartialRelation targetType) {
106 return reference(linkType, sourceType, containment, multiplicity, targetType, null);
107 }
108
109 public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, Multiplicity multiplicity,
110 PartialRelation targetType) {
111 return reference(linkType, sourceType, multiplicity, targetType, null);
112 }
113
114 public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType, boolean containment,
115 PartialRelation targetType) {
116 return reference(linkType, sourceType, containment, targetType, null);
117 }
118
119 public MetamodelBuilder reference(PartialRelation linkType, PartialRelation sourceType,
120 PartialRelation targetType) {
121 return reference(linkType, sourceType, targetType, null);
122 }
123
124 public MetamodelBuilder references(Collection<Map.Entry<PartialRelation, ReferenceInfo>> entries) {
125 for (var entry : entries) {
126 reference(entry.getKey(), entry.getValue());
127 }
128 return this;
129 }
130
131 public MetamodelBuilder references(Map<PartialRelation, ReferenceInfo> map) {
132 return references(map.entrySet());
133 }
134
135 public Metamodel build() {
136 for (var entry : referenceInfoMap.entrySet()) {
137 var linkType = entry.getKey();
138 var info = entry.getValue();
139 processReferenceInfo(linkType, info);
140 }
141 typeHierarchyBuilder.setContainedTypes(containedTypes);
142 var typeHierarchy = typeHierarchyBuilder.build();
143 return new Metamodel(typeHierarchy, Collections.unmodifiableMap(containmentHierarchy),
144 Collections.unmodifiableMap(directedCrossReferences),
145 Collections.unmodifiableMap(undirectedCrossReferences),
146 Collections.unmodifiableMap(oppositeReferences));
147 }
148
149 private void processReferenceInfo(PartialRelation linkType, ReferenceInfo info) {
150 if (oppositeReferences.containsKey(linkType) || containmentHierarchy.containsKey(linkType)) {
151 // We already processed this reference while processing its opposite.
152 return;
153 }
154 var sourceType = info.sourceType();
155 var targetType = info.targetType();
156 if (typeHierarchyBuilder.isInvalidType(sourceType)) {
157 throw new IllegalArgumentException("Source type %s of %s is not in type hierarchy"
158 .formatted(sourceType, linkType));
159 }
160 if (typeHierarchyBuilder.isInvalidType(targetType)) {
161 throw new IllegalArgumentException("Target type %s of %s is not in type hierarchy"
162 .formatted(targetType, linkType));
163 }
164 var opposite = info.opposite();
165 Multiplicity targetMultiplicity = UnconstrainedMultiplicity.INSTANCE;
166 if (opposite != null) {
167 var oppositeInfo = referenceInfoMap.get(opposite);
168 validateOpposite(linkType, info, opposite, oppositeInfo);
169 targetMultiplicity = oppositeInfo.multiplicity();
170 if (oppositeInfo.containment()) {
171 // Skip processing this reference and process it once we encounter its containment opposite.
172 return;
173 }
174 if (opposite.equals(linkType)) {
175 if (!sourceType.equals(targetType)) {
176 throw new IllegalArgumentException("Target %s of undirected reference %s differs from source %s"
177 .formatted(targetType, linkType, sourceType));
178 }
179 undirectedCrossReferences.put(linkType, new UndirectedCrossReferenceInfo(sourceType,
180 info.multiplicity()));
181 return;
182 }
183 oppositeReferences.put(opposite, linkType);
184 }
185 if (info.containment()) {
186 if (targetMultiplicity.multiplicity().meet(CardinalityIntervals.ONE).isEmpty()) {
187 throw new IllegalArgumentException("Invalid opposite %s with multiplicity %s of containment %s"
188 .formatted(opposite, targetMultiplicity, linkType));
189 }
190 containedTypes.add(targetType);
191 containmentHierarchy.put(linkType, new ContainmentInfo(sourceType, info.multiplicity(), targetType));
192 return;
193 }
194 directedCrossReferences.put(linkType, new DirectedCrossReferenceInfo(sourceType, info.multiplicity(),
195 targetType, targetMultiplicity));
196 }
197
198 private static void validateOpposite(PartialRelation linkType, ReferenceInfo info, PartialRelation opposite,
199 ReferenceInfo oppositeInfo) {
200 var sourceType = info.sourceType();
201 var targetType = info.targetType();
202 if (oppositeInfo == null) {
203 throw new IllegalArgumentException("Opposite %s of %s is not defined"
204 .formatted(opposite, linkType));
205 }
206 if (!oppositeInfo.opposite().equals(linkType)) {
207 throw new IllegalArgumentException("Expected %s to have opposite %s, got %s instead"
208 .formatted(opposite, linkType, oppositeInfo.opposite()));
209 }
210 if (!oppositeInfo.sourceType().equals(targetType)) {
211 throw new IllegalArgumentException("Expected %s to have source type %s, got %s instead"
212 .formatted(opposite, targetType, oppositeInfo.sourceType()));
213 }
214 if (!oppositeInfo.targetType().equals(sourceType)) {
215 throw new IllegalArgumentException("Expected %s to have target type %s, got %s instead"
216 .formatted(opposite, sourceType, oppositeInfo.targetType()));
217 }
218 if (oppositeInfo.containment() && info.containment()) {
219 throw new IllegalArgumentException("Opposite %s of containment %s cannot be containment"
220 .formatted(opposite, linkType));
221 }
222 }
223}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelTranslator.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelTranslator.java
new file mode 100644
index 00000000..5afa58f2
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/MetamodelTranslator.java
@@ -0,0 +1,37 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.metamodel;
7
8import tools.refinery.store.model.ModelStoreBuilder;
9import tools.refinery.store.model.ModelStoreConfiguration;
10import tools.refinery.store.reasoning.translator.containment.ContainmentHierarchyTranslator;
11import tools.refinery.store.reasoning.translator.crossreference.DirectedCrossReferenceTranslator;
12import tools.refinery.store.reasoning.translator.crossreference.UndirectedCrossReferenceTranslator;
13import tools.refinery.store.reasoning.translator.opposite.OppositeRelationTranslator;
14import tools.refinery.store.reasoning.translator.typehierarchy.TypeHierarchyTranslator;
15
16public class MetamodelTranslator implements ModelStoreConfiguration {
17 private final Metamodel metamodel;
18
19 public MetamodelTranslator(Metamodel metamodel) {
20 this.metamodel = metamodel;
21 }
22
23 @Override
24 public void apply(ModelStoreBuilder storeBuilder) {
25 storeBuilder.with(new TypeHierarchyTranslator(metamodel.typeHierarchy()));
26 storeBuilder.with(new ContainmentHierarchyTranslator(metamodel.containmentHierarchy()));
27 for (var entry : metamodel.directedCrossReferences().entrySet()) {
28 storeBuilder.with(new DirectedCrossReferenceTranslator(entry.getKey(), entry.getValue()));
29 }
30 for (var entry : metamodel.undirectedCrossReferences().entrySet()) {
31 storeBuilder.with(new UndirectedCrossReferenceTranslator(entry.getKey(), entry.getValue()));
32 }
33 for (var entry : metamodel.oppositeReferences().entrySet()) {
34 storeBuilder.with(new OppositeRelationTranslator(entry.getKey(), entry.getValue()));
35 }
36 }
37}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ReferenceInfo.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ReferenceInfo.java
new file mode 100644
index 00000000..9a6b4012
--- /dev/null
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/metamodel/ReferenceInfo.java
@@ -0,0 +1,13 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.reasoning.translator.metamodel;
7
8import tools.refinery.store.reasoning.representation.PartialRelation;
9import tools.refinery.store.reasoning.translator.multiplicity.Multiplicity;
10
11public record ReferenceInfo(boolean containment, PartialRelation sourceType, Multiplicity multiplicity,
12 PartialRelation targetType, PartialRelation opposite) {
13}