Class AsyncTaskManager<R>
- Type Parameters:
R- asynchronous task result type
VaadinSession lock) entirely within the context of a locked VaadinSession.
Instances of this class manage some background activity or task that is initiated from within a VaadinSession.
The task runs asynchronously in the background without holding the VaadinSession lock. Once completed, the
result is reported back to the locked VaadinSession and the configured
result consumer, if any.
Only one such task is allowed to be executing at any given time: if a second task is started while an existing task is
still in progress, the first task is automatically canceled. Tasks are initiated via startTask()
and may be canceled at any time via cancelTask().
Results returned from successful task executions are delivered to the configured result consumer, if any.
Safety Guarantees
This class handles all required synchronization and locking. It guarantees that at most one background task
can be executing at a time, that all operations are atomic, that listener notifications are delivered in proper order,
and that no race conditions can occur. For example, if a background task tries to report back at the same time a Vaadin
thread invokes cancelTask(), then the task will always appear to have either completed successfully or been canceled.
Instances bind to the current VaadinSession at construction time and may only be used with that session.
If any method is invoked with the wrong VaadinSession locking state, an immediate exception is thrown.
Therefore, thread safety is not only provided but enforced.
If a current UI exists when startTask(org.dellroad.stuff.vaadin24.util.AsyncTask<? extends R>) is invoked, it will also be restored
(along with the current VaadinSession) when any corresponding callbacks are invoked, unless it has since
been detached.
Event Notifications
Instances support event notification via addAsyncTaskStatusChangeListener().
All notifications are delivered within the context of the locked VaadinSession.
On task start, a STARTED notification is generated. When the task finishes,
the outcome - one of: COMPLETED,
CANCELED, or FAILED - is reported.
Proper ordering of event notifications is guaranteed:
- Exactly one
STARTEDnotification and exactly oneCOMPLETED,CANCELED, orFAILEDnotification will be delivered for each task initiated bystartTask(). STARTEDnotifications are always delivered before the correspondingCOMPLETED,CANCELED, orFAILEDnotification for the same task.- The
COMPLETED,CANCELED, orFAILEDnotification for a task is always delivered before theSTARTEDnotification for any subsequent task. - Tasks are executed, and corresponding notifications are delivered, in the same order that they are started.
- See Also:
-
Field Summary
FieldsModifier and TypeFieldDescriptionprotected final VaadinSessionTheVaadinSessionwith which this instance is associated. -
Constructor Summary
ConstructorsConstructorDescriptionDefault constructor.AsyncTaskManager(Function<? super Runnable, ? extends Future<?>> executor) Constructor. -
Method Summary
Modifier and TypeMethodDescriptionAdd aAsyncTaskStatusChangeListenerto this instance.longCancels the current outstanding asynchronous task, if any, and returns its unique ID.longGet the ID of the currently outstanding asynchronous task, if any.Get theVaadinSessionto which this instance is associated.protected voidhandleTaskException(long id, Throwable t) Invoked when an exception other thanInterruptedExceptionis thrown by theAsyncTask.protected voidhandleTaskResult(long id, R result) Process the result from a successfully completed asynchronous task.protected voidinvokeTask(long id, AsyncTask<? extends R> task) Perform the asynchronous task.booleanisBusy()Determine whether there is an outstanding asynchronous task in progress.protected longGet the next unique task ID.protected voidnotifyListeners(UI ui, AsyncTaskStatusChangeEvent<R> event) Notify listeners.protected booleanreportTask(long id, R result, Throwable exception) Report the outcome of an asynchronous task (whether successful or otherwise) back to theVaadinSession.voidsetAsyncExecutor(Function<? super Runnable, ? extends Future<?>> executor) Configure the executor used for async tasks.voidsetResultConsumer(BiConsumer<? super Long, ? super R> resultConsumer) Configure where successful results are delivered.longTrigger execution of a new asynchronous task.protected voidPerform the given action with the givenUIas current, if not null and still associated with the currentVaadinSession.
-
Field Details
-
session
TheVaadinSessionwith which this instance is associated.
-
-
Constructor Details
-
AsyncTaskManager
public AsyncTaskManager()Default constructor.Caller must configure an async executor via
setAsyncExecutor().- Throws:
IllegalStateException- if there is noVaadinSessionassociated with the current thread
-
AsyncTaskManager
Constructor.- Parameters:
executor- the executor used to execute async tasks, or null for none- Throws:
IllegalStateException- if there is noVaadinSessionassociated with the current thread
-
-
Method Details
-
getVaadinSession
Get theVaadinSessionto which this instance is associated.- Returns:
- this instance's
VaadinSession, never null
-
setAsyncExecutor
Configure the executor used for async tasks.The executor must execute tasks with this instance's VaadinSession unlocked.
Note: when an in-progress task is canceled via
cancelTask(), thenFuture.cancel()will be invoked on theFuturereturned by the executor.- Parameters:
executor- the thing that launches background tasks, or null for none
-
setResultConsumer
Configure where successful results are delivered.The given consumer will always be invoked with this instance's VaadinSession locked.
- Parameters:
resultConsumer- recipient for successful task results, taking task ID and result, or null to discard task results
-
startTask
Trigger execution of a new asynchronous task.If there is already an asynchronous task in progress, this method will cancel it first. You can safely check this ahead of time via
isBusy(); this is race-free as long as the session lock is held across both method invocations.- Parameters:
task- performs the desired task and returns some result- Returns:
- unique ID for this task execution
- Throws:
IllegalStateException- if this instance's VaadinSession is not locked by the current threadIllegalStateException- if there is no executor configuredIllegalArgumentException- iftaskis null
-
isBusy
public boolean isBusy()Determine whether there is an outstanding asynchronous task in progress.Equivalent to:
getCurrentTaskId() != 0.- Returns:
- true if an asynchronous task is currently executing, otherwise false
- Throws:
IllegalStateException- if the current thread is not associated with this instance's session
-
getCurrentTaskId
public long getCurrentTaskId()Get the ID of the currently outstanding asynchronous task, if any.- Returns:
- the unique ID of the current asynchronous task, if any, otherwise zero
- Throws:
IllegalStateException- if the current thread is not associated with this instance's session
-
cancelTask
public long cancelTask()Cancels the current outstanding asynchronous task, if any, and returns its unique ID.Any currently executing asynchronous task canceled and
Future.cancel()is invoked on it'sFuture, which may result in the background thread being interrupted.This method guarantees that the corresponding task, if any, will have a
CANCELEDoutcome.- Returns:
- the unique ID of the canceled task, if any, or zero if there is no task outstanding
- Throws:
IllegalStateException- if the current thread is not associated with this instance's session
-
addAsyncTaskStatusChangeListener
Add aAsyncTaskStatusChangeListenerto this instance.- Parameters:
listener- listener for notifications- Returns:
- listener registration
- Throws:
IllegalArgumentException- iflisteneris nullIllegalStateException- if the current thread is not associated with this instance's session
-
nextTaskId
protected long nextTaskId()Get the next unique task ID.Each invocation of this method returns a new value.
- Returns:
- unique task ID, never zero
-
invokeTask
Perform the asynchronous task.This method is invoked in the background, with this instance's session not locked.
When finished (regardless of the outcome) this method invokes
reportTask()with this instance's session locked.- Parameters:
id- task IDtask- task to execute- Throws:
IllegalStateException- if the current thread has this instance's session lockedIllegalArgumentException- ifidis zeroIllegalArgumentException- iftaskis null
-
reportTask
Report the outcome of an asynchronous task (whether successful or otherwise) back to theVaadinSession.This is invoked (indirectly) by
invokeTask()with this instance's session locked.- Parameters:
id- task IDresult- task result; must be null if there was an exceptionexception- thrown exception (InterruptedExceptionif interrupted), or null if there was no exception- Returns:
- true if
idmatched the current task ID, otherwise false - Throws:
IllegalStateException- if the current thread is not associated with this instance's sessionIllegalArgumentException- ifidis zeroIllegalArgumentException- ifresultandexceptionare both not null
-
notifyListeners
Notify listeners.This is invoked with this instance's session locked.
The implementation in
AsyncTaskManageractually delivers the notifications later, in the manner ofVaadinSession.access().- Parameters:
ui-UIto make current, or null for noneevent- status change event- Throws:
IllegalStateException- if the current thread is not associated with this instance's sessionIllegalArgumentException- ifeventis zero
-
handleTaskResult
Process the result from a successfully completed asynchronous task.This is invoked with this instance's session locked.
The implementation in
AsyncTaskManagerpasses the result to the configured result consumer, if any.- Parameters:
id- task IDresult- task result- Throws:
IllegalArgumentException- ifresultis nullIllegalStateException- if the current thread is not associated with this instance's session
-
handleTaskException
Invoked when an exception other thanInterruptedExceptionis thrown by theAsyncTask.Note: this method runs in the background thread and the
VaadinSessionwill not be locked.The implementation in
AsyncTaskManagerjust logs an error.- Parameters:
id- the unique ID of the task that failedt- the exception that was caught
-
withUI
Perform the given action with the givenUIas current, if not null and still associated with the currentVaadinSession.- Parameters:
ui-UIto make current, or null for noneaction- action to perform
-