Class SuppressableCallback<T>
- Type Parameters:
T- the type of return value, oftenVoid
This thing really is a terrible hack, but it becomes necessary when the cause of an event cannot be reliably determined. In cases where the callback (lacking a cause parameter) is expected to be invoked on the same stack as the method calling, this mechanism can optionally suppress that callback.
Suppression is implemented on a per-thread basis, so that suppression requests are only effective when the callback is in fact on the same stack as the request.
A common use case is for a method to suppress any recursive calls, i.e., it is self suppressing, e.g.:
private final SuppressableCallback<Void> cbDoSomething = new SuppressableCallback<>();
public boolean doSomething() {
cbDoSomething.invoke(__ -> {
try (Suppression supp = cbDoSomething.supppress(null)) {
// do the thing
return doAnotherThing();
}
}, false);
}
public boolean doAnotherThing() {
// do the other thing
return doSomething();
}
This example is very trivial, but this sort of thing can easily happen in event driven programming. Consider the case where a state change causes an update to a table selection, which fires the selection changed event, in turn requesting the same state change. Checking for equality of the requested state with the current state can resolve some cases, but such checks are thwarted when any two events requesting unequal state get queued on an event thread, resulting in unending oscillation between the requested states. A more robust solution demands we know the cause(s) of events. For now, the solution is to suppress event firing whenever a state change is due to receiving an event.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classA suppression handle on the callback, for a specific thread -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidRun the given callback unless it has been suppressed<R> RRun the given callback, returning its value, unless it has been suppressedvoidinvokeWithStack(Consumer<List<T>> callback) Run the given callback with the values from the stack of suppression requests<R> RinvokeWithStack(Function<List<T>, R> callback) Run the given callback with the stack, returning its valuevoidinvokeWithTop(Consumer<T> callback) Run the given callback with the topmost suppression value ornullif not suppressed<R> RinvokeWithTop(Function<T, R> callback) Run the given callback with the topmost value, returning its valueSuppress this callback, providing the given value as information
-
Constructor Details
-
SuppressableCallback
public SuppressableCallback()
-
-
Method Details
-
suppress
Suppress this callback, providing the given value as informationThis should almost always be used in a try-with-resources block. The only exception is perhaps to wrap this in another
AutoCloseable. The information is usually one of the parameters, or perhaps a n-tuple of all parameters. For many use cases,nullis all that is needed. The information is needed if the callback would like to make the suppression decision based on that information, e.g., is this callback telling me to "go to" a place I'm already "going to"?- Parameters:
value- the value- Returns:
- a handle to the request
-
invoke
Run the given callback unless it has been suppressedThe values on the stack of suppression requests do not matter. If there's a request, the callback is suppressed.
- Parameters:
callback- the callback
-
invoke
Run the given callback, returning its value, unless it has been suppressedWorks like
invoke(Runnable), except that the callback can return a value. If the callback is suppressed, a fallback value is returned instead.- Type Parameters:
R- the return type- Parameters:
callback- the callbackfallback- a fallback value in case of suppression- Returns:
- the value from the callback, or the fallback value
-
invokeWithTop
Run the given callback with the topmost suppression value ornullif not suppressedThe callback is always invoked, allow it to decide what actions to take (or not take) based on the given value. Not for a
SuppressableCallback<T>, this method is useless, as the provided value will always benull, whether or not suppressed.- Parameters:
callback- the callback
-
invokeWithTop
Run the given callback with the topmost value, returning its valueThis works like
invokeWithTop(Consumer), except that the callback can return a value. Note that a fallback parameter is not taken, since the callback is always invoked. The callback should implement its own fallback logic.- Type Parameters:
R- the return type- Parameters:
callback- the callback- Returns:
- the value from the callback
-
invokeWithStack
Run the given callback with the values from the stack of suppression requestsThe callback is always invoked, allowing it to decide what actions to take (or not take) based on the values present in the stack.
- Parameters:
callback- a method to receive the stack
-
invokeWithStack
Run the given callback with the stack, returning its valueThis works like
invokeWithStack(Consumer), except that the callback can return a value. Note that a fallback parameter is not taken, since the callback is always invoked. The callback should implement its own fallback logic.- Type Parameters:
R- the return type- Parameters:
callback- the callback- Returns:
- the value from the callback
-