context: Use polymorphism instead of canBeCancelled field

This commit is contained in:
Eric Anderson 2017-08-26 13:48:47 -07:00
parent 21cd244734
commit 3620931eae
1 changed files with 14 additions and 27 deletions

View File

@ -106,7 +106,7 @@ public class Context {
* <p>Never assume this is the default context for new threads, because {@link Storage} may define * <p>Never assume this is the default context for new threads, because {@link Storage} may define
* a default context that is different from ROOT. * a default context that is different from ROOT.
*/ */
public static final Context ROOT = new Context(null, EMPTY_ENTRIES, false); public static final Context ROOT = new Context(null, EMPTY_ENTRIES);
// Lazy-loaded storage. Delaying storage initialization until after class initialization makes it // Lazy-loaded storage. Delaying storage initialization until after class initialization makes it
// much easier to avoid circular loading since there can still be references to Context as long as // much easier to avoid circular loading since there can still be references to Context as long as
@ -179,7 +179,6 @@ public class Context {
private ArrayList<ExecutableListener> listeners; private ArrayList<ExecutableListener> listeners;
private CancellationListener parentListener = new ParentListener(); private CancellationListener parentListener = new ParentListener();
private final boolean canBeCancelled;
final CancellableContext cancellableAncestor; final CancellableContext cancellableAncestor;
final PersistentHashArrayMappedTrie<Key<?>, Object> keyValueEntries; final PersistentHashArrayMappedTrie<Key<?>, Object> keyValueEntries;
@ -189,7 +188,6 @@ public class Context {
private Context(PersistentHashArrayMappedTrie<Key<?>, Object> keyValueEntries) { private Context(PersistentHashArrayMappedTrie<Key<?>, Object> keyValueEntries) {
cancellableAncestor = null; cancellableAncestor = null;
this.keyValueEntries = keyValueEntries; this.keyValueEntries = keyValueEntries;
canBeCancelled = false;
} }
/** /**
@ -199,20 +197,6 @@ public class Context {
private Context(Context parent, PersistentHashArrayMappedTrie<Key<?>, Object> keyValueEntries) { private Context(Context parent, PersistentHashArrayMappedTrie<Key<?>, Object> keyValueEntries) {
cancellableAncestor = cancellableAncestor(parent); cancellableAncestor = cancellableAncestor(parent);
this.keyValueEntries = keyValueEntries; this.keyValueEntries = keyValueEntries;
canBeCancelled = cancellableAncestor != null;
}
/**
* Construct a context that can be cancelled and will cascade cancellation from its parent if
* it is cancellable.
*/
private Context(
Context parent,
PersistentHashArrayMappedTrie<Key<?>, Object> keyValueEntries,
boolean isCancellable) {
cancellableAncestor = cancellableAncestor(parent);
this.keyValueEntries = keyValueEntries;
canBeCancelled = isCancellable;
} }
/** /**
@ -357,9 +341,7 @@ public class Context {
} }
boolean canBeCancelled() { boolean canBeCancelled() {
// A context is cancellable if it cascades from its parent and its parent is return cancellableAncestor != null;
// cancellable or is itself directly cancellable..
return canBeCancelled;
} }
/** /**
@ -458,7 +440,7 @@ public class Context {
final Executor executor) { final Executor executor) {
checkNotNull(cancellationListener, "cancellationListener"); checkNotNull(cancellationListener, "cancellationListener");
checkNotNull(executor, "executor"); checkNotNull(executor, "executor");
if (canBeCancelled) { if (canBeCancelled()) {
ExecutableListener executableListener = ExecutableListener executableListener =
new ExecutableListener(executor, cancellationListener); new ExecutableListener(executor, cancellationListener);
synchronized (this) { synchronized (this) {
@ -485,7 +467,7 @@ public class Context {
* Remove a {@link CancellationListener}. * Remove a {@link CancellationListener}.
*/ */
public void removeListener(CancellationListener cancellationListener) { public void removeListener(CancellationListener cancellationListener) {
if (!canBeCancelled) { if (!canBeCancelled()) {
return; return;
} }
synchronized (this) { synchronized (this) {
@ -514,7 +496,7 @@ public class Context {
* any reference to them so that they may be garbage collected. * any reference to them so that they may be garbage collected.
*/ */
void notifyAndClearListeners() { void notifyAndClearListeners() {
if (!canBeCancelled) { if (!canBeCancelled()) {
return; return;
} }
ArrayList<ExecutableListener> tmpListeners; ArrayList<ExecutableListener> tmpListeners;
@ -678,7 +660,7 @@ public class Context {
* Create a cancellable context that does not have a deadline. * Create a cancellable context that does not have a deadline.
*/ */
private CancellableContext(Context parent) { private CancellableContext(Context parent) {
super(parent, parent.keyValueEntries, true); super(parent, parent.keyValueEntries);
deadline = parent.getDeadline(); deadline = parent.getDeadline();
// Create a surrogate that inherits from this to attach so that you cannot retrieve a // Create a surrogate that inherits from this to attach so that you cannot retrieve a
// cancellable context from Context.current() // cancellable context from Context.current()
@ -690,7 +672,7 @@ public class Context {
*/ */
private CancellableContext(Context parent, Deadline deadline, private CancellableContext(Context parent, Deadline deadline,
ScheduledExecutorService scheduler) { ScheduledExecutorService scheduler) {
super(parent, parent.keyValueEntries, true); super(parent, parent.keyValueEntries);
Deadline parentDeadline = parent.getDeadline(); Deadline parentDeadline = parent.getDeadline();
if (parentDeadline != null && parentDeadline.compareTo(deadline) <= 0) { if (parentDeadline != null && parentDeadline.compareTo(deadline) <= 0) {
// The new deadline won't have an effect, so ignore it // The new deadline won't have an effect, so ignore it
@ -813,6 +795,11 @@ public class Context {
public Deadline getDeadline() { public Deadline getDeadline() {
return deadline; return deadline;
} }
@Override
boolean canBeCancelled() {
return true;
}
} }
/** /**
@ -996,14 +983,14 @@ public class Context {
* {@link #cancellableAncestor}. * {@link #cancellableAncestor}.
*/ */
static CancellableContext cancellableAncestor(Context parent) { static CancellableContext cancellableAncestor(Context parent) {
if (parent == null || !parent.canBeCancelled()) { if (parent == null) {
return null; return null;
} }
if (parent instanceof CancellableContext) { if (parent instanceof CancellableContext) {
return (CancellableContext) parent; return (CancellableContext) parent;
} }
// The parent simply cascades cancellations. // The parent simply cascades cancellations.
// Bypass the parent and reference the ancestor directly. // Bypass the parent and reference the ancestor directly (may be null).
return parent.cancellableAncestor; return parent.cancellableAncestor;
} }
} }