Skip to content

Commit 4939db9

Browse files
committed
Replace "read context" with "read session"
1 parent b54dfbb commit 4939db9

File tree

51 files changed

+321
-319
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+321
-319
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,17 @@ public final class ExampleBosk extends Bosk<ExampleState> {
8989
You create an instance of `ExampleBosk` at initialization time,
9090
typically using your application framework's dependency injection system.
9191

92-
To read state, acquire a `ReadContext`, providing access to a lightweight immutable snapshot of your state tree:
92+
To read state, acquire a `ReadSession`, providing access to a lightweight immutable snapshot of your state tree:
9393

9494
```
95-
try (var _ = bosk.readContext()) {
95+
try (var _ = bosk.readSession()) {
9696
System.out.println("Hello, " + bosk.refs.name.value());
9797
}
9898
```
9999

100-
A read context is intended to be coarse-grained, for example covering an entire HTTP request,
100+
A read session is intended to be coarse-grained, for example covering an entire HTTP request,
101101
giving you "snapshot-at-start" semantics and protecting you from race conditions.
102-
It is an antipattern to use many small read contexts during the course of a single operation.
102+
It is an antipattern to use many small sessions during the course of a single operation.
103103

104104
This part is done automatically for you in Spring Boot if you bring in the `bosk-spring-boot` library.
105105
You can also set the `bosk.web.maintenance-path` property to get an immediate HTTP REST API to view and edit your state tree.

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

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import works.bosk.dereferencers.Dereferencer;
3232
import works.bosk.dereferencers.PathCompiler;
3333
import works.bosk.exceptions.InvalidTypeException;
34-
import works.bosk.exceptions.NoReadContextException;
34+
import works.bosk.exceptions.NoReadSessionException;
3535
import works.bosk.exceptions.NonexistentReferenceException;
3636
import works.bosk.exceptions.NotYetImplementedException;
3737
import works.bosk.exceptions.ReferenceBindingException;
@@ -47,7 +47,7 @@
4747

4848
/**
4949
* A mutable container for an immutable object tree with cross-tree {@link Reference}s,
50-
* providing snapshot-at-start semantics via {@link ReadContext ReadContext},
50+
* providing snapshot-at-start semantics via {@link ReadSession ReadSession},
5151
* managing updates via {@link BoskDriver},
5252
* and notifying listeners of changes via {@link #hookRegistrar() hookRegistrar}.
5353
*
@@ -61,7 +61,7 @@
6161
*
6262
* <p>
6363
* Reads are performed by calling {@link Reference#value()} in the context of
64-
* a {@code ReadContext}, which provides an immutable snapshot of the bosk
64+
* a {@code ReadSession}, which provides an immutable snapshot of the bosk
6565
* state to the thread.
6666
* This object acts as a factory for {@link Reference} objects that
6767
* traverse the object trees by walking their fields (actually getter methods)
@@ -72,7 +72,7 @@
7272
* {@link BoskDriver#submitReplacement(Reference, Object) submitReplacement} and similar,
7373
* rather than by modifying the in-memory state directly.
7474
* The driver will apply the changes either immediately or at a later time.
75-
* Regardless, updates will not be visible in any {@code ReadContext}
75+
* Regardless, updates will not be visible in any {@code ReadSession}
7676
* created before the update occurred.
7777
*
7878
* @param <R> The type of the state tree's root node
@@ -366,7 +366,7 @@ public <T> void submitReplacement(Reference<T> target, T newValue) {
366366
public <T> void submitConditionalCreation(Reference<T> target, T newValue) {
367367
synchronized (this) {
368368
boolean preconditionsSatisfied;
369-
try (ReadContext _ = supersedingReadContext()) {
369+
try (ReadSession _ = supersedingReadSession()) {
370370
preconditionsSatisfied = !target.exists();
371371
}
372372
if (preconditionsSatisfied) {
@@ -402,7 +402,7 @@ public void flush() {
402402
public <T> void submitConditionalReplacement(Reference<T> target, T newValue, Reference<Identifier> precondition, Identifier requiredValue) {
403403
synchronized (this) {
404404
boolean preconditionsSatisfied;
405-
try (ReadContext _ = supersedingReadContext()) {
405+
try (ReadSession _ = supersedingReadSession()) {
406406
preconditionsSatisfied = Objects.equals(precondition.valueIfExists(), requiredValue);
407407
}
408408
if (preconditionsSatisfied) {
@@ -420,7 +420,7 @@ public <T> void submitConditionalReplacement(Reference<T> target, T newValue, Re
420420
public <T> void submitConditionalDeletion(Reference<T> target, Reference<Identifier> precondition, Identifier requiredValue) {
421421
synchronized (this) {
422422
boolean preconditionsSatisfied;
423-
try (ReadContext _ = supersedingReadContext()) {
423+
try (ReadSession _ = supersedingReadSession()) {
424424
preconditionsSatisfied = Objects.equals(precondition.value(), requiredValue);
425425
}
426426
if (preconditionsSatisfied) {
@@ -521,7 +521,7 @@ private <T, S> void triggerQueueingOfHooks(Reference<T> target, @Nullable R prio
521521
hookExecutionQueue.addLast(() -> {
522522
// We use two nested try statements here so that the "finally" clause runs within the diagnostic scope
523523
try (DiagnosticScope _ = diagnosticContext.withOnly(attributes)) {
524-
try (ReadContext _ = new ReadContext(rootForHook)) {
524+
try (ReadSession _ = new ReadSession(rootForHook)) {
525525
LOGGER.debug("Hook: RUN {}({})", reg.name, changedRef);
526526
reg.hook.onChanged(changedRef);
527527
} catch (Exception e) {
@@ -797,7 +797,7 @@ public String toString() {
797797
* @param effectiveScope The hook scope with zero or more of its parameters filled in
798798
* @param priorRoot The root before the change that triggered the hook; or null during initialization when running
799799
* hooks on the {@link BoskDriver#initialRoot initial root}.
800-
* @param newRoot The root after the change that triggered the hook. This will be the root in the {@link ReadContext}
800+
* @param newRoot The root after the change that triggered the hook. This will be the root in the {@link ReadSession}
801801
* during hook execution.
802802
* @param action The operation to perform for each matching object that is different between the two roots
803803
* @param <S> The type of the hook scope object
@@ -860,36 +860,36 @@ private <V> V refValueIfExists(Reference<V> containerRef, @Nullable R root) {
860860
return null;
861861
} else {
862862
// TODO: This would be less cumbersome if we could apply a Reference to an arbitrary root object.
863-
// For now, References only apply to the current ReadContext, so we need a new ReadContext every time
863+
// For now, References only apply to the current ReadSession, so we need a new ReadSession every time
864864
// we want to change roots.
865-
try (var _ = new ReadContext(root)) {
865+
try (var _ = new ReadSession(root)) {
866866
return containerRef.valueIfExists();
867867
}
868868
}
869869
}
870870

871871
/**
872872
* A thread-local region in which {@link Reference#value()} works; outside
873-
* of a {@code ReadContext}, {@link Reference#value()} will throw {@link
873+
* of a {@code ReadSession}, {@link Reference#value()} will throw {@link
874874
* IllegalStateException}.
875875
*
876876
* @author pdoyle
877877
*/
878-
public final class ReadContext implements AutoCloseable {
878+
public final class ReadSession implements AutoCloseable {
879879
final R originalRoot;
880880
final R snapshot; // Mostly for adopt()
881881

882882
/**
883-
* Creates a {@link ReadContext} for the current thread. If one is already
883+
* Creates a {@link ReadSession} for the current thread. If one is already
884884
* active on this thread, the new nested one will be equivalent and has
885885
* no effect.
886886
*/
887-
private ReadContext() {
887+
private ReadSession() {
888888
originalRoot = rootSnapshot.get();
889889
if (originalRoot == null) {
890890
snapshot = currentRoot;
891891
if (snapshot == null) {
892-
throw new IllegalStateException("Bosk constructor has not yet finished; cannot create a ReadContext");
892+
throw new IllegalStateException("Bosk constructor has not yet finished; cannot create a ReadSession");
893893
}
894894
rootSnapshot.set(snapshot);
895895
LOGGER.trace("New {}", this);
@@ -900,7 +900,7 @@ private ReadContext() {
900900
}
901901
}
902902

903-
private ReadContext(ReadContext toAdopt) {
903+
private ReadSession(ReadSession toAdopt) {
904904
R snapshotToInherit = requireNonNull(toAdopt.snapshot);
905905
originalRoot = rootSnapshot.get();
906906
if (originalRoot == null) {
@@ -922,117 +922,117 @@ private ReadContext(ReadContext toAdopt) {
922922
* Unlike the other constructors, this can be used to substitute a new root temporarily,
923923
* even if there's already one active on the current thread.
924924
*/
925-
ReadContext(@NotNull R root) {
925+
ReadSession(@NotNull R root) {
926926
originalRoot = rootSnapshot.get();
927927
snapshot = requireNonNull(root);
928928
rootSnapshot.set(snapshot);
929929
LOGGER.trace("Using {}", this);
930930
}
931931

932932
/**
933-
* Creates a {@link ReadContext} for the current thread, inheriting state
933+
* Creates a {@link ReadSession} for the current thread, inheriting state
934934
* from another thread.
935935
* Any calls to {@link Reference#value()} on the current thread will return
936936
* the same value they would have returned on the thread where
937-
* <code>this</code> context was created.
937+
* <code>this</code> session was created.
938938
*
939939
* <p>
940-
* Because nested scopes behave like their outer scope, you can always
941-
* make another ReadContext at any time on some thread in order to
942-
* "capture" whatever scope may be in effect on that thread (or to
940+
* Because nested sessions behave like their outer session, you can always
941+
* make another ReadSession at any time on some thread to
942+
* "capture" whatever session may be in effect on that thread (or to
943943
* create a new one if there is no active scope on that thread).
944944
*
945945
* <p>
946-
* Hence, a recommended idiom for scope inheritance looks like this:
946+
* Hence, a recommended idiom for session inheritance looks like this:
947947
*
948948
* <blockquote><pre>
949-
* try (ReadContext originalThReadContext = bosk.readContext()) {
949+
* try (ReadSession originalThReadSession = bosk.readSession()) {
950950
* workQueue.submit(() -> {
951-
* try (ReadContext workerThReadContext = bosk.adopt(originalThReadContext)) {
951+
* try (ReadSession workerThReadSession = bosk.adopt(originalThReadSession)) {
952952
* // Code in here can read from the bosk just like the original thread.
953953
* }
954954
* });
955955
* }
956956
* </pre></blockquote>
957957
*
958958
* Note, though, that this will prevent the garbage collector from
959-
* collecting the ReadContext's state snapshot until the worker thread's
959+
* collecting the ReadSession's state snapshot until the worker thread's
960960
* scope is finished. Therefore, if the worker thread is to continue running
961961
* after the original thread would have exited its own scope,
962962
* then use this idiom only if the worker thread must see
963963
* the same state snapshot as the original thread <em>and</em> you're
964964
* willing to prevent that snapshot from being garbage-collected until
965965
* the worker thread finishes.
966966
*
967-
* @return a <code>ReadContext</code> representing the new context.
967+
* @return a <code>ReadSession</code> representing the new session.
968968
*/
969-
public ReadContext adopt() {
970-
return new ReadContext(this);
969+
public ReadSession adopt() {
970+
return new ReadSession(this);
971971
}
972972

973973
@Override
974974
public void close() {
975-
// TODO: Enforce the closing rules described in readContext javadocs?
975+
// TODO: Enforce the closing rules described in readSession javadocs?
976976
LOGGER.trace("Exiting {}; restoring {}", this, System.identityHashCode(originalRoot));
977977
rootSnapshot.set(originalRoot);
978978
}
979979

980980
@Override
981981
public String toString() {
982-
return "ReadContext(" + System.identityHashCode(snapshot) + ")";
982+
return "ReadSession(" + System.identityHashCode(snapshot) + ")";
983983
}
984984
}
985985

986986
/**
987-
* Establishes a {@link ReadContext} for the calling thread,
987+
* Establishes a {@link ReadSession} for the calling thread,
988988
* allowing {@link Reference#value()} to return values from this bosk's state tree,
989989
* from a snapshot taken at the moment this method was called.
990-
* The snapshot is held stable until the returned context is {@link ReadContext#close() closed}.
990+
* The snapshot is held stable until the returned session is {@link ReadSession#close() closed}.
991991
*
992992
* <p>
993-
* If the calling thread has an active read context already,
994-
* the returned <code>ReadContext</code> has no effect:
995-
* the state snapshot from the existing context will continue to be used on the calling thread
996-
* until both contexts (the returned one and the existing one) are closed.
993+
* If the calling thread has an active session already,
994+
* the returned <code>ReadSession</code> has no effect:
995+
* the state snapshot from the existing session will continue to be used on the calling thread
996+
* until both sessions (the returned one and the existing one) are closed.
997997
*
998998
* <p>
999-
* <code>ReadContext</code>s must be closed on the same thread on which they were opened,
999+
* <code>ReadSession</code>s must be closed on the same thread on which they were opened,
10001000
* and must be closed in reverse order.
10011001
* We recommend using them in <i>try-with-resources</i> statements;
1002-
* otherwise, you could end up with some read contexts ending prematurely,
1002+
* otherwise, you could end up with some sessions ending prematurely,
10031003
* and others persisting for the remainder of the thread's lifetime.
10041004
*/
1005-
public final ReadContext readContext() {
1006-
return new ReadContext();
1005+
public final ReadSession readSession() {
1006+
return new ReadSession();
10071007
}
10081008

10091009
/**
1010-
* Establishes a new {@link ReadContext} for the calling thread, similar to {@link #readContext()}, except that
1011-
* if the calling thread already has a context, it will be ignored,
1012-
* and the newly created context will have a fresh snapshot of the bosk's state tree;
1013-
* then, when the returned context is {@link ReadContext#close closed},
1014-
* the previous context will be restored.
1010+
* Establishes a new {@link ReadSession} for the calling thread, similar to {@link #readSession()}, except that
1011+
* if the calling thread already has a session, it will be ignored,
1012+
* and the newly created session will have a fresh snapshot of the bosk's state tree;
1013+
* then, when the returned session is {@link ReadSession#close closed},
1014+
* the previous session will be restored.
10151015
* <p>
10161016
* This is intended to support coordination of distributed logic among multiple threads (or servers) using the same bosk.
10171017
* Threads can submit an update, call {@link BoskDriver#flush}, and then use this method
10181018
* to inspect the bosk state and determine what effect the update had.
10191019
* <p>
10201020
* Use this method when it's important to observe the bosk state after a {@link BoskDriver#flush flush}
10211021
* performed by the same thread.
1022-
* When in doubt, you probably want {@link #readContext()} instead of this.
1022+
* When in doubt, you probably want {@link #readSession()} instead of this.
10231023
* This method opens the possibility that the same thread can see two different revisions of the bosk state,
10241024
* which can lead to confusing bugs in application code.
1025-
* In addition, when the returned context is {@link ReadContext#close closed},
1025+
* In addition, when the returned session is {@link ReadSession#close closed},
10261026
* the bosk state can appear to revert to a prior state, which can be confusing.
10271027
*
1028-
* @see #readContext()
1028+
* @see #readSession()
10291029
*/
1030-
public final ReadContext supersedingReadContext() {
1030+
public final ReadSession supersedingReadSession() {
10311031
R snapshot = currentRoot;
10321032
if (snapshot == null) {
1033-
throw new IllegalStateException("Bosk constructor has not yet finished; cannot create a ReadContext");
1033+
throw new IllegalStateException("Bosk constructor has not yet finished; cannot create a ReadSession");
10341034
}
1035-
return new ReadContext(snapshot);
1035+
return new ReadSession(snapshot);
10361036
}
10371037

10381038
/**
@@ -1296,7 +1296,7 @@ public T valueIfExists() {
12961296
R snapshot = rootSnapshot.get();
12971297
LOGGER.trace("Snapshot is {}", System.identityHashCode(snapshot));
12981298
if (snapshot == null) {
1299-
throw new NoReadContextException("No active read context for " + name + " in " + Thread.currentThread());
1299+
throw new NoReadSessionException("No active read session for " + name + " in " + Thread.currentThread());
13001300
} else try {
13011301
return (T) dereferencer().get(snapshot, this);
13021302
} catch (NonexistentEntryException e) {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public interface BoskDriver {
4949
* Requests that the object referenced by <code>target</code> be changed to <code>newValue</code>.
5050
*
5151
* <p>
52-
* Changes will not be visible in the {@link Bosk.ReadContext} in which this method
52+
* Changes will not be visible in the {@link Bosk.ReadSession} in which this method
5353
* was called. If <code>target</code> is inside an enclosing object that does not exist at the
5454
* time the update is applied, it is silently ignored.
5555
*/
@@ -78,7 +78,7 @@ public interface BoskDriver {
7878
* it will be changed to {@link java.util.Optional#empty()}.
7979
*
8080
* <p>
81-
* Changes will not be visible in the {@link Bosk.ReadContext} in which this method
81+
* Changes will not be visible in the {@link Bosk.ReadSession} in which this method
8282
* was called. If <code>target.exists()</code> is false at the time this update
8383
* is to be applied, it is silently ignored.
8484
*
@@ -123,7 +123,7 @@ public interface BoskDriver {
123123
* </li></ul>
124124
*
125125
* All of these events "happen before" this method returns.
126-
* If a {@link Bosk.ReadContext} is acquired after this method returns,
126+
* If a {@link Bosk.ReadSession} is acquired after this method returns,
127127
* all of the effects of the above operations (and possibly some additional subsequent operations)
128128
* will be reflected in the bosk state.
129129
* Hooks triggered by the above operations may or may not have run before this method returns.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* know the key for each entry: its {@link Entity#id}.
2727
*
2828
* <p>
29-
* Because a <code>Catalog</code> <em>contains</em> its entries, a {@link Bosk.ReadContext}
29+
* Because a <code>Catalog</code> <em>contains</em> its entries, a {@link Bosk.ReadSession}
3030
* is not required to access them.
3131
*
3232
* @author pdoyle

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public interface HookRegistrar {
1111
* <p>
1212
* The <code>scope</code> reference can be parameterized.
1313
* Upon any change to any matching node, or any parent or child of a matching node,
14-
* the <code>hook</code> will be called with a {@link Bosk.ReadContext} that captures
14+
* the <code>hook</code> will be called with a {@link Bosk.ReadSession} that captures
1515
* the state immediately after the update was applied.
1616
* The <code>hook</code> will receive an argument that is the <code>scope</code> reference
1717
* with all its parameters (if any) bound.

0 commit comments

Comments
 (0)