Skip to content

Commit bd64346

Browse files
committed
Add registrar factory to Bosk constructor
1 parent ead5361 commit bd64346

File tree

30 files changed

+243
-119
lines changed

30 files changed

+243
-119
lines changed

bosk-core/src/main/java/works/bosk/Bosk.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ public class Bosk<R extends StateTreeNode> implements BoskInfo<R> {
9191
private final LocalDriver localDriver;
9292
private final RootRef rootRef;
9393
private final ThreadLocal<R> rootSnapshot = new ThreadLocal<>();
94+
private final HookRegistrar hookRegistrar;
9495
private final Queue<HookRegistration<?>> hooks = new ConcurrentLinkedQueue<>();
9596
private final ExecutorService hookExecutor = Executors.newVirtualThreadPerTaskExecutor();
9697
private final PathCompiler pathCompiler;
@@ -112,7 +113,7 @@ public class Bosk<R extends StateTreeNode> implements BoskInfo<R> {
112113
* @see DriverStack
113114
*/
114115
@SuppressWarnings("this-escape")
115-
public Bosk(String name, Type rootType, DefaultRootFunction<R> defaultRootFunction, DriverFactory<R> driverFactory) {
116+
public Bosk(String name, Type rootType, DefaultRootFunction<R> defaultRootFunction, DriverFactory<R> driverFactory, RegistrarFactory registrarFactory) {
116117
this.name = name;
117118
this.pathCompiler = PathCompiler.withSourceType(rootType); // Required before rootRef
118119
this.localDriver = new LocalDriver(defaultRootFunction);
@@ -131,6 +132,7 @@ public Bosk(String name, Type rootType, DefaultRootFunction<R> defaultRootFuncti
131132
// initialization to have completed already.
132133
//
133134
this.driver = new ValidatingDriver(driverFactory.build(boskInfo, this.localDriver));
135+
this.hookRegistrar = registrarFactory.build(boskInfo, this::localRegisterHook);
134136

135137
try {
136138
this.currentRoot = rootRef.targetClass().cast(requireNonNull(driver.initialRoot(rootType)));
@@ -145,6 +147,14 @@ public Bosk(String name, Type rootType, DefaultRootFunction<R> defaultRootFuncti
145147
boskInfo.boskRef().set(this); // @SuppressWarnings("this-escape")
146148
}
147149

150+
/**
151+
* @deprecated This constructor is going to be removed. You can inline it into your code to get its replacement.
152+
*/
153+
@Deprecated(forRemoval = true)
154+
public Bosk(String name, Type rootType, DefaultRootFunction<R> defaultRootFunction, DriverFactory<R> driverFactory) {
155+
this(name, rootType, defaultRootFunction, driverFactory, Bosk.simpleRegistrar());
156+
}
157+
148158
public interface DefaultRootFunction<RR extends StateTreeNode> {
149159
RR apply(Bosk<RR> bosk) throws InvalidTypeException;
150160
}
@@ -184,6 +194,13 @@ public static <RR extends StateTreeNode> DriverFactory<RR> simpleDriver() {
184194
return (b,d) -> d;
185195
}
186196

197+
/**
198+
* @return a {@link RegistrarFactory} with only the basic functionality.
199+
*/
200+
public static RegistrarFactory simpleRegistrar() {
201+
return (b,d) -> d;
202+
}
203+
187204
/**
188205
* Provides access to the {@link BoskDriver} object to use for submitting updates to this bosk's state tree.
189206
* <p>
@@ -634,6 +651,13 @@ public String toString() {
634651
*
635652
*/
636653
public <T> void registerHook(String name, @NonNull Reference<T> scope, @NonNull BoskHook<T> action) {
654+
hookRegistrar.registerHook(name, scope, action);
655+
}
656+
657+
/**
658+
* The unadorned version of {@link #registerHook} that simply registers the hook as given.
659+
*/
660+
private <T> void localRegisterHook(String name, @NotNull Reference<T> scope, @NotNull BoskHook<T> action) {
637661
HookRegistration<T> reg = new HookRegistration<>(name, requireNonNull(scope), requireNonNull(action));
638662
hooks.add(reg);
639663
localDriver.triggerEverywhere(reg);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package works.bosk;
2+
3+
public interface HookRegistrar {
4+
<T> void registerHook(String name, Reference<T> scope, BoskHook<T> hook);
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package works.bosk;
2+
3+
public interface RegistrarFactory {
4+
HookRegistrar build(BoskInfo<?> boskInfo, HookRegistrar downstream);
5+
}

bosk-core/src/test/java/works/bosk/BoskConstructorTest.java

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,15 @@ void basicProperties_correctValues() {
3131
StateTreeNode root = newEntity();
3232

3333
AtomicReference<BoskDriver> driver = new AtomicReference<>();
34-
Bosk<StateTreeNode> bosk = new Bosk<StateTreeNode>(
34+
Bosk<StateTreeNode> bosk = new Bosk<>(
3535
name,
3636
rootType,
3737
_ -> root,
38-
(_, d)-> {
38+
(_, d) -> {
3939
driver.set(new ForwardingDriver(d));
4040
return driver.get();
41-
});
41+
},
42+
Bosk.simpleRegistrar());
4243

4344
assertEquals(name, bosk.name());
4445
assertEquals(rootType, bosk.rootReference().targetType());
@@ -64,7 +65,8 @@ void invalidRootType_throws() {
6465
boskName("Invalid root type"),
6566
TypeValidationTest.ArrayField.class,
6667
bosk -> new TypeValidationTest.ArrayField(Identifier.from("test"), new String[0]),
67-
Bosk.simpleDriver()));
68+
Bosk.simpleDriver(),
69+
Bosk.simpleRegistrar()));
6870
}
6971

7072
@Test
@@ -86,23 +88,24 @@ void badDefaultRootFunction_throws() {
8688
@Test
8789
void mismatchedRootType_throws() {
8890
assertThrows(ClassCastException.class, ()->
89-
new Bosk<Entity> (
91+
new Bosk<Entity>(
9092
boskName("Mismatched root"),
91-
BoxedPrimitives.class, // Valid but wrong
93+
BoxedPrimitives.class,
9294
bosk -> newEntity(),
93-
Bosk.simpleDriver()
94-
)
95+
Bosk.simpleDriver(),
96+
Bosk.simpleRegistrar())
9597
);
9698
}
9799

98100
@Test
99101
void driverInitialRoot_matches() {
100102
SimpleTypes root = newEntity();
101-
Bosk<StateTreeNode> bosk = new Bosk<StateTreeNode>(
103+
Bosk<StateTreeNode> bosk = new Bosk<>(
102104
boskName(),
103105
SimpleTypes.class,
104-
_ -> {throw new AssertionError("Shouldn't be called");},
105-
initialRootDriver(()->root));
106+
_ -> { throw new AssertionError("Shouldn't be called"); },
107+
initialRootDriver(() -> root),
108+
Bosk.simpleRegistrar());
106109
try (var _ = bosk.readContext()) {
107110
assertSame(root, bosk.rootReference().value());
108111
}
@@ -112,14 +115,14 @@ void driverInitialRoot_matches() {
112115
void defaultRoot_matches() {
113116
SimpleTypes root = newEntity();
114117
{
115-
Bosk<StateTreeNode> valueBosk = new Bosk<>(boskName(), SimpleTypes.class, _ -> root, Bosk.simpleDriver());
118+
Bosk<StateTreeNode> valueBosk = new Bosk<>(boskName(), SimpleTypes.class, _ -> root, Bosk.simpleDriver(), Bosk.simpleRegistrar());
116119
try (var _ = valueBosk.readContext()) {
117120
assertSame(root, valueBosk.rootReference().value());
118121
}
119122
}
120123

121124
{
122-
Bosk<StateTreeNode> functionBosk = new Bosk<StateTreeNode>(boskName(), SimpleTypes.class, _ -> root, Bosk.simpleDriver());
125+
Bosk<StateTreeNode> functionBosk = new Bosk<StateTreeNode>(boskName(), SimpleTypes.class, _ -> root, Bosk.simpleDriver(), Bosk.simpleRegistrar());
123126
try (var _ = functionBosk.readContext()) {
124127
assertSame(root, functionBosk.rootReference().value());
125128
}
@@ -139,8 +142,8 @@ private static void assertInitialRootThrows(Class<? extends Throwable> expectedT
139142
boskName(),
140143
SimpleTypes.class,
141144
_ -> newEntity(),
142-
initialRootDriver(initialRootFunction)
143-
));
145+
initialRootDriver(initialRootFunction),
146+
Bosk.simpleRegistrar()));
144147
}
145148

146149
/**
@@ -151,8 +154,8 @@ private static void assertDefaultRootThrows(Class<? extends Throwable> expectedT
151154
boskName(),
152155
SimpleTypes.class,
153156
defaultRootFunction,
154-
Bosk.simpleDriver()
155-
));
157+
Bosk.simpleDriver(),
158+
Bosk.simpleRegistrar()));
156159
}
157160

158161
@NotNull

bosk-core/src/test/java/works/bosk/BoskDiagnosticContextTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ void setupBosk() {
2929
boskName(),
3030
TestEntity.class,
3131
AbstractDriverTest::initialRoot,
32-
Bosk.simpleDriver()
33-
);
32+
Bosk.simpleDriver(),
33+
Bosk.simpleRegistrar());
3434
}
3535

3636
@Test

bosk-core/src/test/java/works/bosk/BoskLocalReferenceTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public interface Refs {
6161
void initializeBosk() throws InvalidTypeException {
6262
boskName = boskName();
6363
Root initialRoot = new Root(1, Catalog.empty());
64-
bosk = new Bosk<>(boskName, Root.class, _ -> initialRoot, Bosk.simpleDriver());
64+
bosk = new Bosk<>(boskName, Root.class, _ -> initialRoot, Bosk.simpleDriver(), Bosk.simpleRegistrar());
6565
refs = bosk.rootReference().buildReferences(Refs.class);
6666
Identifier ernieID = Identifier.from("ernie");
6767
Identifier bertID = Identifier.from("bert");

bosk-core/src/test/java/works/bosk/BoskUpdateTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ public interface Refs {
3939

4040
@BeforeEach
4141
void createBosk() throws InvalidTypeException {
42-
bosk = new Bosk<TestRoot>(
42+
bosk = new Bosk<>(
4343
boskName(),
4444
TestRoot.class,
4545
AbstractBoskTest::initialRoot,
46-
Bosk.simpleDriver()
47-
);
46+
Bosk.simpleDriver(),
47+
Bosk.simpleRegistrar());
4848
refs = bosk.buildReferences(Refs.class);
4949
try (var _ = bosk.readContext()) {
5050
originalRoot = bosk.rootReference().value();

bosk-core/src/test/java/works/bosk/CatalogBenchmark.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ public static class BenchmarkState {
2929

3030
@Setup(Level.Trial)
3131
public void setup() throws InvalidTypeException {
32-
Bosk<AbstractBoskTest.TestRoot> bosk = new Bosk<AbstractBoskTest.TestRoot>(
32+
Bosk<AbstractBoskTest.TestRoot> bosk = new Bosk<>(
3333
boskName(),
3434
AbstractBoskTest.TestRoot.class,
3535
AbstractBoskTest::initialRoot,
36-
Bosk.simpleDriver()
37-
);
36+
Bosk.simpleDriver(),
37+
Bosk.simpleRegistrar());
3838
TestEntityBuilder teb = new TestEntityBuilder(bosk);
3939
int initialSize = 100_000;
4040
catalog = Catalog.of(IntStream.rangeClosed(1, initialSize).mapToObj(i ->

bosk-core/src/test/java/works/bosk/ListingTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
5050
return childrenStream
5151
.map(children -> {
5252
TestEntity root = new TestEntity(Identifier.unique("parent"), Catalog.of(children));
53-
Bosk<TestEntity> bosk = new Bosk<>(boskName(), TestEntity.class, _ -> root, Bosk.simpleDriver());
53+
Bosk<TestEntity> bosk = new Bosk<>(boskName(), TestEntity.class, _ -> root, Bosk.simpleDriver(), Bosk.simpleRegistrar());
5454
CatalogReference<TestEntity> catalog;
5555
try {
5656
catalog = bosk.rootReference().thenCatalog(TestEntity.class, Path.just(TestEntity.Fields.children));
@@ -69,7 +69,7 @@ public Stream<? extends Arguments> provideArguments(ExtensionContext context) th
6969
TestEntity child = new TestEntity(Identifier.unique("child"), Catalog.empty());
7070
List<TestEntity> children = singletonList(child);
7171
TestEntity root = new TestEntity(Identifier.unique("parent"), Catalog.of(children));
72-
Bosk<TestEntity> bosk = new Bosk<>(boskName(), TestEntity.class, _ -> root, Bosk.simpleDriver());
72+
Bosk<TestEntity> bosk = new Bosk<>(boskName(), TestEntity.class, _ -> root, Bosk.simpleDriver(), Bosk.simpleRegistrar());
7373
CatalogReference<TestEntity> childrenRef = bosk.rootReference().thenCatalog(TestEntity.class, Path.just(TestEntity.Fields.children));
7474
return idStreams().map(list -> Arguments.of(list.map(Identifier::from).collect(toList()), childrenRef, bosk));
7575
}
@@ -242,7 +242,7 @@ void testEmpty() throws InvalidTypeException {
242242
TestEntity child = new TestEntity(Identifier.unique("child"), Catalog.empty());
243243
List<TestEntity> children = singletonList(child);
244244
TestEntity root = new TestEntity(Identifier.unique("parent"), Catalog.of(children));
245-
Bosk<TestEntity> bosk = new Bosk<>(boskName(), TestEntity.class, _ -> root, Bosk.simpleDriver());
245+
Bosk<TestEntity> bosk = new Bosk<>(boskName(), TestEntity.class, _ -> root, Bosk.simpleDriver(), Bosk.simpleRegistrar());
246246
CatalogReference<TestEntity> childrenRef = bosk.rootReference().thenCatalog(TestEntity.class, Path.just(TestEntity.Fields.children));
247247

248248
Listing<TestEntity> actual = Listing.empty(childrenRef);

bosk-core/src/test/java/works/bosk/OptionalRefsTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class OptionalRefsTest extends AbstractRoundTripTest {
1818

1919
@Test
2020
void testReferenceOptionalNotAllowed() {
21-
Bosk<OptionalString> bosk = new Bosk<>(boskName(), OptionalString.class, _ -> new OptionalString(ID, Optional.empty()), Bosk.simpleDriver());
21+
Bosk<OptionalString> bosk = new Bosk<>(boskName(), OptionalString.class, _ -> new OptionalString(ID, Optional.empty()), Bosk.simpleDriver(), Bosk.simpleRegistrar());
2222
InvalidTypeException e = assertThrows(InvalidTypeException.class, () -> bosk.rootReference().then(Optional.class, Path.just("field")));
2323
assertThat(e.getMessage(), containsString("not supported"));
2424
}
@@ -100,7 +100,7 @@ private interface ValueFactory<R extends Entity, V> {
100100
}
101101

102102
private <E extends Entity, V> void doTest(E initialRoot, ValueFactory<E, V> valueFactory, DriverFactory<E> driverFactory) throws InvalidTypeException {
103-
Bosk<E> bosk = new Bosk<>(boskName(), initialRoot.getClass(), _ -> initialRoot, driverFactory);
103+
Bosk<E> bosk = new Bosk<>(boskName(), initialRoot.getClass(), _ -> initialRoot, driverFactory, Bosk.simpleRegistrar());
104104
V value = valueFactory.createFrom(bosk);
105105
@SuppressWarnings("unchecked")
106106
Reference<V> optionalRef = bosk.rootReference().then((Class<V>)value.getClass(), "field");

0 commit comments

Comments
 (0)