aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-04-21 02:12:04 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-04-21 02:34:52 +0200
commitea0f09096afe05e2d414c707584e1e33c0c44383 (patch)
tree60763156db85be14e34aaf1b504ccbd1faad8bff /subprojects/store
parentfix: REAL_SUM input and result type (diff)
downloadrefinery-ea0f09096afe05e2d414c707584e1e33c0c44383.tar.gz
refinery-ea0f09096afe05e2d414c707584e1e33c0c44383.tar.zst
refinery-ea0f09096afe05e2d414c707584e1e33c0c44383.zip
refactor: simplify ModelAdapter
* Remove the reflection-based machinery around adapter types. * Adapter builders, store adapters, and model adapters are now only associated with each other based on static and runtime types. * Simplifies writing new adapters. * Hierarchical syntax for adding adapter builders to the store builder.
Diffstat (limited to 'subprojects/store')
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java42
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java102
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterUtils.java33
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java24
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java11
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java19
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java84
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/Model.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java8
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java20
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java59
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java26
13 files changed, 111 insertions, 327 deletions
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java
index 70602ef5..8d3e998e 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java
@@ -1,32 +1,48 @@
1package tools.refinery.store.adapter;
1/* 2/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> 3 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 * 4 *
4 * SPDX-License-Identifier: EPL-2.0 5 * SPDX-License-Identifier: EPL-2.0
5 */ 6 */
6package tools.refinery.store.adapter;
7
8import tools.refinery.store.model.ModelStore; 7import tools.refinery.store.model.ModelStore;
9import tools.refinery.store.model.ModelStoreBuilder; 8import tools.refinery.store.model.ModelStoreBuilder;
10 9
11public abstract class AbstractModelAdapterBuilder implements ModelAdapterBuilder { 10public abstract class AbstractModelAdapterBuilder<T extends ModelStoreAdapter> implements ModelAdapterBuilder {
12 private final ModelStoreBuilder storeBuilder; 11 private boolean configured;
13 12
14 protected AbstractModelAdapterBuilder(ModelStoreBuilder storeBuilder) { 13 @Override
15 this.storeBuilder = storeBuilder; 14 public boolean isConfigured() {
15 return configured;
16 } 16 }
17 17
18 @Override 18 protected void checkConfigured() {
19 public <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory) { 19 if (!configured) {
20 return storeBuilder.with(adapterBuilderFactory); 20 throw new IllegalStateException("Model adapter builder was not configured");
21 }
22 }
23
24 protected void checkNotConfigured() {
25 if (configured) {
26 throw new IllegalStateException("Model adapter builder was already configured");
27 }
28 }
29
30 protected void doConfigure(ModelStoreBuilder storeBuilder) {
31 // Nothing to configure by default.
21 } 32 }
22 33
23 @Override 34 @Override
24 public ModelStoreBuilder getStoreBuilder() { 35 public final void configure(ModelStoreBuilder storeBuilder) {
25 return storeBuilder; 36 checkNotConfigured();
37 doConfigure(storeBuilder);
38 configured = true;
26 } 39 }
27 40
41 protected abstract T doBuild(ModelStore store);
42
28 @Override 43 @Override
29 public ModelStore build() { 44 public final T build(ModelStore store) {
30 return storeBuilder.build(); 45 checkConfigured();
46 return doBuild(store);
31 } 47 }
32} 48}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java
deleted file mode 100644
index e896d8d9..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java
+++ /dev/null
@@ -1,102 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.adapter;
7
8import org.jetbrains.annotations.NotNull;
9
10import java.util.*;
11import java.util.function.Consumer;
12
13public class AdapterList<T> implements Iterable<T> {
14 private final List<AnyModelAdapterType> adapterTypes;
15 private final List<T> adapters;
16
17 public AdapterList() {
18 adapterTypes = new ArrayList<>();
19 adapters = new ArrayList<>();
20 }
21
22 public AdapterList(int adapterCount) {
23 adapterTypes = new ArrayList<>(adapterCount);
24 adapters = new ArrayList<>(adapterCount);
25 }
26
27 public int size() {
28 return adapters.size();
29 }
30
31 public void add(AnyModelAdapterType adapterType, T adapter) {
32 adapterTypes.add(adapterType);
33 adapters.add(adapter);
34 }
35
36 public <U extends T> Optional<U> tryGet(AnyModelAdapterType adapterType, Class<? extends U> adapterClass) {
37 int size = size();
38 for (int i = 0; i < size; i++) {
39 if (getType(i).supports(adapterType)) {
40 return Optional.of(adapterClass.cast(get(i)));
41 }
42 }
43 return Optional.empty();
44 }
45
46 public <U extends T> U get(AnyModelAdapterType adapterType, Class<U> adapterClass) {
47 return tryGet(adapterType, adapterClass).orElseThrow(() -> new IllegalArgumentException(
48 "No %s was configured".formatted(adapterType)));
49 }
50
51 public AnyModelAdapterType getType(int i) {
52 return adapterTypes.get(i);
53 }
54
55 public T get(int i) {
56 return adapters.get(i);
57 }
58
59 public Collection<AnyModelAdapterType> getAdapterTypes() {
60 return Collections.unmodifiableCollection(adapterTypes);
61 }
62
63 public Iterable<Entry<T>> withAdapterTypes() {
64 return () -> new Iterator<>() {
65 private int i = 0;
66
67 @Override
68 public boolean hasNext() {
69 return i < size();
70 }
71
72 @Override
73 public Entry<T> next() {
74 if (i >= size()) {
75 throw new NoSuchElementException();
76 }
77 var entry = new Entry<>(getType(i), get(i));
78 i++;
79 return entry;
80 }
81 };
82 }
83
84 @NotNull
85 @Override
86 public Iterator<T> iterator() {
87 return adapters.iterator();
88 }
89
90 @Override
91 public void forEach(Consumer<? super T> action) {
92 adapters.forEach(action);
93 }
94
95 @Override
96 public Spliterator<T> spliterator() {
97 return adapters.spliterator();
98 }
99
100 public record Entry<T>(AnyModelAdapterType adapterType, T adapter) {
101 }
102}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterUtils.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterUtils.java
new file mode 100644
index 00000000..556e99f0
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterUtils.java
@@ -0,0 +1,33 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.adapter;
7
8import java.util.Collection;
9import java.util.Optional;
10
11public class AdapterUtils {
12 private AdapterUtils() {
13 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
14 }
15
16 public static <T, U extends T> Optional<U> tryGetAdapter(Collection<T> adapters, Class<? extends U> type) {
17 var iterator = adapters.stream().filter(type::isInstance).iterator();
18 if (!iterator.hasNext()) {
19 return Optional.empty();
20 }
21 var adapter = type.cast(iterator.next());
22 if (iterator.hasNext()) {
23 throw new IllegalArgumentException("Ambiguous adapter: both %s and %s match %s"
24 .formatted(adapter.getClass().getName(), iterator.next().getClass().getName(), type.getName()));
25 }
26 return Optional.of(adapter);
27 }
28
29 public static <T> T getAdapter(Collection<? super T> adapters, Class<T> type) {
30 return tryGetAdapter(adapters, type).orElseThrow(() -> new IllegalArgumentException(
31 "No %s adapter was configured".formatted(type.getName())));
32 }
33}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java
deleted file mode 100644
index f161a60b..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java
+++ /dev/null
@@ -1,24 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.adapter;
7
8import java.util.Collection;
9
10public sealed interface AnyModelAdapterType permits ModelAdapterType {
11 Class<? extends ModelAdapter> getModelAdapterClass();
12
13 Class<? extends ModelStoreAdapter> getModelStoreAdapterClass();
14
15 Class<? extends ModelAdapterBuilder> getModelAdapterBuilderClass();
16
17 Collection<AnyModelAdapterType> getSupportedAdapterTypes();
18
19 default boolean supports(AnyModelAdapterType targetAdapter) {
20 return getSupportedAdapterTypes().contains(targetAdapter);
21 }
22
23 String getName();
24}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java
index 709cbb3e..75e5e07d 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java
@@ -9,14 +9,9 @@ import tools.refinery.store.model.ModelStore;
9import tools.refinery.store.model.ModelStoreBuilder; 9import tools.refinery.store.model.ModelStoreBuilder;
10 10
11public interface ModelAdapterBuilder { 11public interface ModelAdapterBuilder {
12 ModelStoreAdapter createStoreAdapter(ModelStore store); 12 boolean isConfigured();
13 13
14 <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory); 14 void configure(ModelStoreBuilder storeBuilder);
15 15
16 ModelStoreBuilder getStoreBuilder(); 16 ModelStoreAdapter build(ModelStore store);
17
18 default void configure() {
19 }
20
21 ModelStore build();
22} 17}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java
deleted file mode 100644
index 1d549d5b..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java
+++ /dev/null
@@ -1,19 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.adapter;
7
8import tools.refinery.store.model.ModelStoreBuilder;
9
10public abstract class ModelAdapterBuilderFactory<T1 extends ModelAdapter, T2 extends ModelStoreAdapter,
11 T3 extends ModelAdapterBuilder> extends ModelAdapterType<T1, T2, T3> {
12
13 protected ModelAdapterBuilderFactory(Class<T1> modelAdapterClass, Class<T2> modelStoreAdapterClass,
14 Class<T3> modelAdapterBuilderClass) {
15 super(modelAdapterClass, modelStoreAdapterClass, modelAdapterBuilderClass);
16 }
17
18 public abstract T3 createBuilder(ModelStoreBuilder storeBuilder);
19}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java
deleted file mode 100644
index 6255fe52..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java
+++ /dev/null
@@ -1,84 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.adapter;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.model.ModelStore;
10
11import java.lang.reflect.Method;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.HashSet;
15import java.util.Set;
16
17public abstract non-sealed class ModelAdapterType<T1 extends ModelAdapter, T2 extends ModelStoreAdapter,
18 T3 extends ModelAdapterBuilder> implements AnyModelAdapterType {
19 private final Class<? extends T1> modelAdapterClass;
20 private final Class<? extends T2> modelStoreAdapterClass;
21 private final Class<? extends T3> modelAdapterBuilderClass;
22 private final Set<AnyModelAdapterType> supportedAdapters = new HashSet<>();
23
24 protected ModelAdapterType(Class<T1> modelAdapterClass, Class<T2> modelStoreAdapterClass,
25 Class<T3> modelAdapterBuilderClass) {
26 checkReturnType(modelAdapterClass, modelStoreAdapterClass, "createModelAdapter", Model.class);
27 checkReturnType(modelStoreAdapterClass, modelAdapterBuilderClass, "createStoreAdapter", ModelStore.class);
28 this.modelAdapterClass = modelAdapterClass;
29 this.modelStoreAdapterClass = modelStoreAdapterClass;
30 this.modelAdapterBuilderClass = modelAdapterBuilderClass;
31 supportedAdapters.add(this);
32 }
33
34 private void checkReturnType(Class<?> expectedReturnType, Class<?> ownerClass, String methodName,
35 Class<?>... argumentTypes) {
36 Method method;
37 try {
38 method = ownerClass.getMethod(methodName, argumentTypes);
39 } catch (NoSuchMethodException e) {
40 throw new IllegalStateException("Invalid %s: %s#%s method is required"
41 .formatted(this, ownerClass.getName(), methodName), e);
42 }
43 var returnType = method.getReturnType();
44 if (!expectedReturnType.isAssignableFrom(returnType)) {
45 throw new IllegalStateException("Invalid %s: %s is not assignable from the return type %s of %s#%s"
46 .formatted(this, expectedReturnType.getName(), returnType.getCanonicalName(),
47 ownerClass.getName(), methodName));
48 }
49 }
50
51 protected void extendsAdapter(ModelAdapterType<? super T1, ? super T2, ? super T3> superAdapter) {
52 supportedAdapters.addAll(superAdapter.supportedAdapters);
53 }
54
55 @Override
56 public final Class<? extends T1> getModelAdapterClass() {
57 return modelAdapterClass;
58 }
59
60 @Override
61 public final Class<? extends T2> getModelStoreAdapterClass() {
62 return modelStoreAdapterClass;
63 }
64
65 @Override
66 public final Class<? extends T3> getModelAdapterBuilderClass() {
67 return modelAdapterBuilderClass;
68 }
69
70 @Override
71 public Collection<AnyModelAdapterType> getSupportedAdapterTypes() {
72 return Collections.unmodifiableCollection(supportedAdapters);
73 }
74
75 @Override
76 public String getName() {
77 return "%s.ADAPTER".formatted(this.getClass().getName());
78 }
79
80 @Override
81 public String toString() {
82 return getName();
83 }
84}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
index f4131756..d58d91c3 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
@@ -6,7 +6,6 @@
6package tools.refinery.store.model; 6package tools.refinery.store.model;
7 7
8import tools.refinery.store.adapter.ModelAdapter; 8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.adapter.ModelAdapterType;
10import tools.refinery.store.map.Versioned; 9import tools.refinery.store.map.Versioned;
11import tools.refinery.store.representation.AnySymbol; 10import tools.refinery.store.representation.AnySymbol;
12import tools.refinery.store.representation.Symbol; 11import tools.refinery.store.representation.Symbol;
@@ -30,9 +29,9 @@ public interface Model extends Versioned {
30 29
31 ModelDiffCursor getDiffCursor(long to); 30 ModelDiffCursor getDiffCursor(long to);
32 31
33 <T extends ModelAdapter> Optional<T> tryGetAdapter(ModelAdapterType<? extends T, ?, ?> adapterType); 32 <T extends ModelAdapter> Optional<T> tryGetAdapter(Class<? extends T> adapterType);
34 33
35 <T extends ModelAdapter> T getAdapter(ModelAdapterType<T, ?, ?> adapterType); 34 <T extends ModelAdapter> T getAdapter(Class<T> adapterType);
36 35
37 void addListener(ModelListener listener); 36 void addListener(ModelListener listener);
38 37
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
index a72399f7..b10eb8a4 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
@@ -5,7 +5,6 @@
5 */ 5 */
6package tools.refinery.store.model; 6package tools.refinery.store.model;
7 7
8import tools.refinery.store.adapter.ModelAdapterType;
9import tools.refinery.store.adapter.ModelStoreAdapter; 8import tools.refinery.store.adapter.ModelStoreAdapter;
10import tools.refinery.store.model.internal.ModelStoreBuilderImpl; 9import tools.refinery.store.model.internal.ModelStoreBuilderImpl;
11import tools.refinery.store.representation.AnySymbol; 10import tools.refinery.store.representation.AnySymbol;
@@ -25,9 +24,9 @@ public interface ModelStore {
25 24
26 ModelDiffCursor getDiffCursor(long from, long to); 25 ModelDiffCursor getDiffCursor(long from, long to);
27 26
28 <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(ModelAdapterType<?, ? extends T, ?> adapterType); 27 <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(Class<? extends T> adapterType);
29 28
30 <T extends ModelStoreAdapter> T getAdapter(ModelAdapterType<?, T, ?> adapterType); 29 <T extends ModelStoreAdapter> T getAdapter(Class<T> adapterType);
31 30
32 static ModelStoreBuilder builder() { 31 static ModelStoreBuilder builder() {
33 return new ModelStoreBuilderImpl(); 32 return new ModelStoreBuilderImpl();
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java
index d9354bdb..3a4024b5 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java
@@ -6,8 +6,6 @@
6package tools.refinery.store.model; 6package tools.refinery.store.model;
7 7
8import tools.refinery.store.adapter.ModelAdapterBuilder; 8import tools.refinery.store.adapter.ModelAdapterBuilder;
9import tools.refinery.store.adapter.ModelAdapterBuilderFactory;
10import tools.refinery.store.adapter.ModelAdapterType;
11import tools.refinery.store.representation.AnySymbol; 9import tools.refinery.store.representation.AnySymbol;
12import tools.refinery.store.representation.Symbol; 10import tools.refinery.store.representation.Symbol;
13 11
@@ -31,11 +29,11 @@ public interface ModelStoreBuilder {
31 29
32 <T> ModelStoreBuilder symbol(Symbol<T> symbol); 30 <T> ModelStoreBuilder symbol(Symbol<T> symbol);
33 31
34 <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory); 32 <T extends ModelAdapterBuilder> ModelStoreBuilder with(T adapterBuilder);
35 33
36 <T extends ModelAdapterBuilder> Optional<T> tryGetAdapter(ModelAdapterType<?, ?, ? extends T> adapterType); 34 <T extends ModelAdapterBuilder> Optional<T> tryGetAdapter(Class<? extends T> adapterType);
37 35
38 <T extends ModelAdapterBuilder> T getAdapter(ModelAdapterType<?, ?, T> adapterType); 36 <T extends ModelAdapterBuilder> T getAdapter(Class<T> adapterType);
39 37
40 ModelStore build(); 38 ModelStore build();
41} 39}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
index 50a408da..c5475a1a 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
@@ -5,10 +5,8 @@
5 */ 5 */
6package tools.refinery.store.model.internal; 6package tools.refinery.store.model.internal;
7 7
8import tools.refinery.store.adapter.AdapterList; 8import tools.refinery.store.adapter.AdapterUtils;
9import tools.refinery.store.adapter.AnyModelAdapterType;
10import tools.refinery.store.adapter.ModelAdapter; 9import tools.refinery.store.adapter.ModelAdapter;
11import tools.refinery.store.adapter.ModelAdapterType;
12import tools.refinery.store.map.DiffCursor; 10import tools.refinery.store.map.DiffCursor;
13import tools.refinery.store.model.*; 11import tools.refinery.store.model.*;
14import tools.refinery.store.representation.AnySymbol; 12import tools.refinery.store.representation.AnySymbol;
@@ -21,7 +19,7 @@ public class ModelImpl implements Model {
21 private final ModelStore store; 19 private final ModelStore store;
22 private long state; 20 private long state;
23 private Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations; 21 private Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations;
24 private final AdapterList<ModelAdapter> adapters; 22 private final List<ModelAdapter> adapters;
25 private final List<ModelListener> listeners = new ArrayList<>(); 23 private final List<ModelListener> listeners = new ArrayList<>();
26 private boolean uncommittedChanges; 24 private boolean uncommittedChanges;
27 private ModelAction pendingAction = ModelAction.NONE; 25 private ModelAction pendingAction = ModelAction.NONE;
@@ -30,7 +28,7 @@ public class ModelImpl implements Model {
30 ModelImpl(ModelStore store, long state, int adapterCount) { 28 ModelImpl(ModelStore store, long state, int adapterCount) {
31 this.store = store; 29 this.store = store;
32 this.state = state; 30 this.state = state;
33 adapters = new AdapterList<>(adapterCount); 31 adapters = new ArrayList<>(adapterCount);
34 } 32 }
35 33
36 void setInterpretations(Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations) { 34 void setInterpretations(Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations) {
@@ -167,17 +165,17 @@ public class ModelImpl implements Model {
167 } 165 }
168 166
169 @Override 167 @Override
170 public <T extends ModelAdapter> Optional<T> tryGetAdapter(ModelAdapterType<? extends T, ?, ?> adapterType) { 168 public <T extends ModelAdapter> Optional<T> tryGetAdapter(Class<? extends T> adapterType) {
171 return adapters.tryGet(adapterType, adapterType.getModelAdapterClass()); 169 return AdapterUtils.tryGetAdapter(adapters, adapterType);
172 } 170 }
173 171
174 @Override 172 @Override
175 public <T extends ModelAdapter> T getAdapter(ModelAdapterType<T, ?, ?> adapterType) { 173 public <T extends ModelAdapter> T getAdapter(Class<T> adapterType) {
176 return adapters.get(adapterType, adapterType.getModelAdapterClass()); 174 return AdapterUtils.getAdapter(adapters, adapterType);
177 } 175 }
178 176
179 void addAdapter(AnyModelAdapterType adapterType, ModelAdapter adapter) { 177 void addAdapter(ModelAdapter adapter) {
180 adapters.add(adapterType, adapter); 178 adapters.add(adapter);
181 } 179 }
182 180
183 @Override 181 @Override
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
index 70bccb96..aafbe130 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
@@ -5,10 +5,8 @@
5 */ 5 */
6package tools.refinery.store.model.internal; 6package tools.refinery.store.model.internal;
7 7
8import tools.refinery.store.adapter.AdapterList; 8import tools.refinery.store.adapter.AdapterUtils;
9import tools.refinery.store.adapter.ModelAdapterBuilder; 9import tools.refinery.store.adapter.ModelAdapterBuilder;
10import tools.refinery.store.adapter.ModelAdapterBuilderFactory;
11import tools.refinery.store.adapter.ModelAdapterType;
12import tools.refinery.store.map.VersionedMapStore; 10import tools.refinery.store.map.VersionedMapStore;
13import tools.refinery.store.map.VersionedMapStoreImpl; 11import tools.refinery.store.map.VersionedMapStoreImpl;
14import tools.refinery.store.model.ModelStore; 12import tools.refinery.store.model.ModelStore;
@@ -23,7 +21,7 @@ import java.util.*;
23public class ModelStoreBuilderImpl implements ModelStoreBuilder { 21public class ModelStoreBuilderImpl implements ModelStoreBuilder {
24 private final Set<AnySymbol> allSymbols = new HashSet<>(); 22 private final Set<AnySymbol> allSymbols = new HashSet<>();
25 private final Map<SymbolEquivalenceClass<?>, List<AnySymbol>> equivalenceClasses = new HashMap<>(); 23 private final Map<SymbolEquivalenceClass<?>, List<AnySymbol>> equivalenceClasses = new HashMap<>();
26 private final AdapterList<ModelAdapterBuilder> adapters = new AdapterList<>(); 24 private final List<ModelAdapterBuilder> adapters = new ArrayList<>();
27 25
28 @Override 26 @Override
29 public <T> ModelStoreBuilder symbol(Symbol<T> symbol) { 27 public <T> ModelStoreBuilder symbol(Symbol<T> symbol) {
@@ -38,46 +36,25 @@ public class ModelStoreBuilderImpl implements ModelStoreBuilder {
38 } 36 }
39 37
40 @Override 38 @Override
41 public <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory) { 39 public <T extends ModelAdapterBuilder> ModelStoreBuilder with(T adapterBuilder) {
42 return adapters.<T>tryGet(adapterBuilderFactory, adapterBuilderFactory.getModelAdapterBuilderClass()) 40 for (var existingAdapter : adapters) {
43 .orElseGet(() -> addAdapter(adapterBuilderFactory)); 41 if (existingAdapter.getClass().equals(adapterBuilder.getClass())) {
44 } 42 throw new IllegalArgumentException("%s adapter was already configured for store builder"
45 43 .formatted(adapterBuilder.getClass().getName()));
46 private <T extends ModelAdapterBuilder> T addAdapter(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory) {
47 for (var configuredAdapterType : adapters.getAdapterTypes()) {
48 var intersection = new HashSet<>(adapterBuilderFactory.getSupportedAdapterTypes());
49 intersection.retainAll(configuredAdapterType.getSupportedAdapterTypes());
50 if (!intersection.isEmpty()) {
51 if (configuredAdapterType.supports(adapterBuilderFactory)) {
52 // Impossible to end up here from <code>#with</code>, because we should have returned
53 // the existing adapter there instead of adding a new one.
54 throw new IllegalArgumentException(
55 "Cannot add %s, because it is already provided by configured adapter %s"
56 .formatted(adapterBuilderFactory, configuredAdapterType));
57 } else if (adapterBuilderFactory.supports(configuredAdapterType)) {
58 throw new IllegalArgumentException(
59 "Cannot add %s, because it provides already configured adapter %s"
60 .formatted(adapterBuilderFactory, configuredAdapterType));
61 } else {
62 throw new IllegalArgumentException(
63 "Cannot add %s, because configured adapter %s already provides %s"
64 .formatted(adapterBuilderFactory, configuredAdapterType, intersection));
65 }
66 } 44 }
67 } 45 }
68 var newAdapter = adapterBuilderFactory.createBuilder(this); 46 adapters.add(adapterBuilder);
69 adapters.add(adapterBuilderFactory, newAdapter); 47 return this;
70 return newAdapter;
71 } 48 }
72 49
73 @Override 50 @Override
74 public <T extends ModelAdapterBuilder> Optional<T> tryGetAdapter(ModelAdapterType<?, ?, ? extends T> adapterType) { 51 public <T extends ModelAdapterBuilder> Optional<T> tryGetAdapter(Class<? extends T> adapterType) {
75 return adapters.tryGet(adapterType, adapterType.getModelAdapterBuilderClass()); 52 return AdapterUtils.tryGetAdapter(adapters, adapterType);
76 } 53 }
77 54
78 @Override 55 @Override
79 public <T extends ModelAdapterBuilder> T getAdapter(ModelAdapterType<?, ?, T> adapterType) { 56 public <T extends ModelAdapterBuilder> T getAdapter(Class<T> adapterType) {
80 return adapters.get(adapterType, adapterType.getModelAdapterBuilderClass()); 57 return AdapterUtils.getAdapter(adapters, adapterType);
81 } 58 }
82 59
83 @Override 60 @Override
@@ -86,13 +63,13 @@ public class ModelStoreBuilderImpl implements ModelStoreBuilder {
86 for (var entry : equivalenceClasses.entrySet()) { 63 for (var entry : equivalenceClasses.entrySet()) {
87 createStores(stores, entry.getKey(), entry.getValue()); 64 createStores(stores, entry.getKey(), entry.getValue());
88 } 65 }
89 var modelStore = new ModelStoreImpl(stores, adapters.size());
90 for (int i = adapters.size() - 1; i >= 0; i--) { 66 for (int i = adapters.size() - 1; i >= 0; i--) {
91 adapters.get(i).configure(); 67 adapters.get(i).configure(this);
92 } 68 }
93 for (var entry : adapters.withAdapterTypes()) { 69 var modelStore = new ModelStoreImpl(stores, adapters.size());
94 var adapter = entry.adapter().createStoreAdapter(modelStore); 70 for (var adapterBuilder : adapters) {
95 modelStore.addAdapter(entry.adapterType(), adapter); 71 var storeAdapter = adapterBuilder.build(modelStore);
72 modelStore.addAdapter(storeAdapter);
96 } 73 }
97 return modelStore; 74 return modelStore;
98 } 75 }
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
index bfae7181..60b735e6 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
@@ -5,9 +5,7 @@
5 */ 5 */
6package tools.refinery.store.model.internal; 6package tools.refinery.store.model.internal;
7 7
8import tools.refinery.store.adapter.AdapterList; 8import tools.refinery.store.adapter.AdapterUtils;
9import tools.refinery.store.adapter.AnyModelAdapterType;
10import tools.refinery.store.adapter.ModelAdapterType;
11import tools.refinery.store.adapter.ModelStoreAdapter; 9import tools.refinery.store.adapter.ModelStoreAdapter;
12import tools.refinery.store.map.DiffCursor; 10import tools.refinery.store.map.DiffCursor;
13import tools.refinery.store.map.VersionedMapStore; 11import tools.refinery.store.map.VersionedMapStore;
@@ -21,11 +19,11 @@ import java.util.*;
21 19
22public class ModelStoreImpl implements ModelStore { 20public class ModelStoreImpl implements ModelStore {
23 private final Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores; 21 private final Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores;
24 private final AdapterList<ModelStoreAdapter> adapters; 22 private final List<ModelStoreAdapter> adapters;
25 23
26 ModelStoreImpl(Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores, int adapterCount) { 24 ModelStoreImpl(Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores, int adapterCount) {
27 this.stores = stores; 25 this.stores = stores;
28 adapters = new AdapterList<>(adapterCount); 26 adapters = new ArrayList<>(adapterCount);
29 } 27 }
30 28
31 @Override 29 @Override
@@ -64,9 +62,9 @@ public class ModelStoreImpl implements ModelStore {
64 } 62 }
65 63
66 private void adaptModel(ModelImpl model) { 64 private void adaptModel(ModelImpl model) {
67 for (var entry : adapters.withAdapterTypes()) { 65 for (var storeAdapter : adapters) {
68 var adapter = entry.adapter().createModelAdapter(model); 66 var adapter = storeAdapter.createModelAdapter(model);
69 model.addAdapter(entry.adapterType(), adapter); 67 model.addAdapter(adapter);
70 } 68 }
71 } 69 }
72 70
@@ -91,16 +89,16 @@ public class ModelStoreImpl implements ModelStore {
91 } 89 }
92 90
93 @Override 91 @Override
94 public <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(ModelAdapterType<?, ? extends T, ?> adapterType) { 92 public <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(Class<? extends T> adapterType) {
95 return adapters.tryGet(adapterType, adapterType.getModelStoreAdapterClass()); 93 return AdapterUtils.tryGetAdapter(adapters, adapterType);
96 } 94 }
97 95
98 @Override 96 @Override
99 public <T extends ModelStoreAdapter> T getAdapter(ModelAdapterType<?, T, ?> adapterType) { 97 public <T extends ModelStoreAdapter> T getAdapter(Class<T> adapterType) {
100 return adapters.get(adapterType, adapterType.getModelStoreAdapterClass()); 98 return AdapterUtils.getAdapter(adapters, adapterType);
101 } 99 }
102 100
103 void addAdapter(AnyModelAdapterType adapterType, ModelStoreAdapter adapter) { 101 void addAdapter(ModelStoreAdapter adapter) {
104 adapters.add(adapterType, adapter); 102 adapters.add(adapter);
105 } 103 }
106} 104}