Skip to content

Commit ca77ab0

Browse files
committed
Wrap remove with UI.accessSynchronous and remove AsyncTask.sync
1 parent 48e015f commit ca77ab0

File tree

3 files changed

+30
-78
lines changed

3 files changed

+30
-78
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ ui.access(() -> {
1212
});
1313
```
1414
While it will make load time much faster, there is a problem there: since the UI is
15-
blocked by computation thread, user will have to wait for finish before his actions
15+
blocked by computation thread, user will have to wait for it to finish before his actions
1616
will be processed. That is, he will see the same loading indicator if he, for example,
1717
click some button that has server side click listener.
1818

@@ -54,7 +54,7 @@ addBeforeLeaveListener(event -> ui.setPollingInterval(-1));
5454
```
5555
See how easy our 4 line snippet turns to 10 line monster? And what if we have
5656
several of those worker threads? Moreover, even if we have push enabled, something
57-
should terminate threads when it's result is not needed anymore (i.e. user has left the view).
57+
should terminate threads when their results are not needed anymore (i.e. user has left the view).
5858

5959
But wander no more, there is an easy solution: **Async Manager**. It is really easy to use:
6060
```java
@@ -68,7 +68,7 @@ termination. For polling mode it also supports
6868
dynamic polling intervals: i.e. you can have 5 polls per second in the
6969
first second and then throttle it to send poll requests once per second:
7070
```java
71-
AsyncManager.setPollingIntervals(200,200,200,200,200,1000);
71+
AsyncManager.setPollingIntervals(200, 200, 200, 200, 200, 1000);
7272
```
7373

7474
It is also possible to set custom exception handler if you
@@ -77,8 +77,8 @@ want some custom logging or exception reporting:
7777
AsyncManager.setExceptionHandler(exception -> ...);
7878
```
7979

80-
By default all worker threads are started by `ThreadPoolExecutor` which defaults
81-
to pool size of 25 threads. You can access instance of executor with
80+
Note: By default all worker threads are started by `ThreadPoolExecutor` which defaults
81+
to pool size of 25 threads. If you want to increase it or change other settings, you can access instance of executor with
8282
`AsyncManager.getExecutor()`.
8383

8484
## Development instructions

src/main/java/org/vaadin/flow/helper/AsyncManager.java

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import com.vaadin.external.org.slf4j.LoggerFactory;
44
import com.vaadin.flow.component.Component;
55
import com.vaadin.flow.component.UI;
6-
import com.vaadin.flow.server.Command;
76

87
import java.io.Serializable;
98
import java.util.*;
@@ -49,31 +48,16 @@ public class AsyncManager implements Serializable {
4948
* @return {@link AsyncTask}, associated with this action
5049
*/
5150
public static AsyncTask register(Component component, AsyncAction action) {
52-
return register(component, false, action);
53-
}
54-
55-
/**
56-
* Register and start a new deferred action. Action are started immediately in a separate thread and do not hold
57-
* {@code UI} or {@code VaadinSession} locks. Polling mode can be forced for this action even if push is enabled,
58-
* which allows to use {@link AsyncTask#sync(Command)} for doing UI operations requiring access to {@code VaadinResponse}
59-
* (for example, to add a cookie)
60-
*
61-
* @param component Component, where the action needs to be performed, typically your view
62-
* @param forcePolling If <tt>true</tt>, polling will be used even if push is enabled
63-
* @param action Action
64-
* @return {@link AsyncTask}, associated with this action
65-
*/
66-
public static AsyncTask register(Component component, boolean forcePolling, AsyncAction action) {
6751
Objects.requireNonNull(component);
6852

6953
AsyncTask asyncTask = new AsyncTask();
70-
Optional<UI> uiOptional = component.getUI();
71-
if (uiOptional.isPresent()) {
72-
asyncTask.register(uiOptional.get(), component, forcePolling, action);
54+
UI ui = component.getUI().orElse(null);
55+
if (ui != null) {
56+
asyncTask.register(ui, component, action);
7357
} else {
7458
component.addAttachListener(attachEvent -> {
7559
attachEvent.unregisterListener();
76-
asyncTask.register(attachEvent.getUI(), component, forcePolling, action);
60+
asyncTask.register(attachEvent.getUI(), component, action);
7761
});
7862
}
7963
return asyncTask;
@@ -173,8 +157,8 @@ private static Set<AsyncTask> getAsyncTasks(UI ui) {
173157
/**
174158
* Add {@link AsyncTask} to the {@link #asyncTasks} for current component
175159
*
176-
* @param ui Owning UI
177-
* @param task Task
160+
* @param ui Owning UI
161+
* @param task Task
178162
*/
179163
static void addAsyncTask(UI ui, AsyncTask task) {
180164
AsyncManager.getAsyncTasks(ui).add(task);
@@ -183,8 +167,8 @@ static void addAsyncTask(UI ui, AsyncTask task) {
183167
/**
184168
* Remove {@link AsyncTask} from the {@link #asyncTasks} for current component
185169
*
186-
* @param ui Owning UI
187-
* @param task Task
170+
* @param ui Owning UI
171+
* @param task Task
188172
*/
189173
static void removeAsyncTask(UI ui, AsyncTask task) {
190174
AsyncManager.getAsyncTasks(ui).remove(task);
@@ -193,7 +177,7 @@ static void removeAsyncTask(UI ui, AsyncTask task) {
193177
/**
194178
* Adjust polling interval for specified component.
195179
*
196-
* @param ui UI, associated with current task
180+
* @param ui UI, associated with current task
197181
*/
198182
static void adjustPollingInterval(UI ui) {
199183
int newInterval = AsyncManager.getAsyncTasks(ui).stream()

src/main/java/org/vaadin/flow/helper/AsyncTask.java

Lines changed: 16 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
/**
1212
* Asynchronous task created by {@link AsyncManager#register(Component, AsyncAction)} or
13-
* {@link AsyncManager#register(Component, boolean, AsyncAction)}.
13+
* {@link AsyncManager#register(Component, AsyncAction)}.
1414
*
1515
* @author Artem Godin
1616
* @see AsyncManager
@@ -22,24 +22,6 @@ public class AsyncTask {
2222
AsyncTask() {
2323
}
2424

25-
/**
26-
* Perform command in {@code VaadinRequest} context. That requires the AsyncTask to be registered
27-
* in a polling mode. The command will be executed in PollEvent listener meaning that
28-
* {@link UI#accessSynchronously(Command)} is not needed.
29-
*
30-
* @param command Command to run
31-
*/
32-
public void sync(Command command) {
33-
if (parentUI == null) return;
34-
if (missedPolls == PUSH_ACTIVE) {
35-
throw new IllegalStateException("Sync is called but task is not in polling mode");
36-
}
37-
if (syncCommand != null) {
38-
throw new IllegalStateException("Sync can be used only once");
39-
}
40-
syncCommand = command;
41-
}
42-
4325
/**
4426
* Perform command in UI context. It uses {@link UI#accessSynchronously(Command)} internally.
4527
*
@@ -49,9 +31,9 @@ public void push(Command command) {
4931
if (parentUI == null) return;
5032
if (missedPolls == PUSH_ACTIVE && parentUI.getPushConfiguration().getPushMode() == PushMode.MANUAL) {
5133
parentUI.accessSynchronously(() -> {
52-
command.execute();
34+
command.execute();
5335
parentUI.push();
54-
});
36+
});
5537
} else {
5638
// Automatic -- changes will be pushed automatically
5739
// Disabled -- we're using polling and this is called
@@ -107,11 +89,6 @@ private void execute() {
10789
*/
10890
private Registration beforeLeaveListenerRegistration;
10991

110-
/**
111-
* Command that needs to be executed in VaadinRequest context
112-
*/
113-
private Command syncCommand;
114-
11592
/**
11693
* Number of poll events happened while action is executing, or {@link #PUSH_ACTIVE} if
11794
* push is used for current task
@@ -121,13 +98,12 @@ private void execute() {
12198
/**
12299
* Register action
123100
*
124-
* @param ui UI owning current view
125-
* @param forcePolling <tt>true</tt> if polling must be used
126-
* @param action Action
101+
* @param ui UI owning current view
102+
* @param action Action
127103
*/
128-
void register(UI ui, Component component, boolean forcePolling, AsyncAction action) {
104+
void register(UI ui, Component component, AsyncAction action) {
129105
this.parentUI = ui;
130-
if (!forcePolling && ui.getPushConfiguration().getPushMode().isEnabled()) {
106+
if (ui.getPushConfiguration().getPushMode().isEnabled()) {
131107
registerPush(component, action);
132108
} else {
133109
registerPoll(component, action);
@@ -191,9 +167,7 @@ private FutureTask<AsyncTask> createFutureTask(AsyncAction action) {
191167
// Dump
192168
AsyncManager.handleException(e);
193169
} finally {
194-
if (syncCommand == null && !Thread.currentThread().isInterrupted()) {
195-
remove();
196-
}
170+
remove();
197171
}
198172
}, this);
199173
}
@@ -213,17 +187,19 @@ private synchronized void remove() {
213187
AsyncManager.removeAsyncTask(parentUI, this);
214188
// Polling interval needs to be adjusted if task is finished
215189
try {
216-
parentUI.accessSynchronously(() -> AsyncManager.adjustPollingInterval(parentUI));
190+
parentUI.accessSynchronously(() -> {
191+
AsyncManager.adjustPollingInterval(parentUI);
192+
193+
if (componentDetachListenerRegistration != null) componentDetachListenerRegistration.remove();
194+
if (uiDetachListenerRegistration != null) uiDetachListenerRegistration.remove();
195+
if (pollingListenerRegistration != null) pollingListenerRegistration.remove();
196+
if (beforeLeaveListenerRegistration != null) beforeLeaveListenerRegistration.remove();
197+
});
217198
} catch (UIDetachedException ignore) {
218199
// ignore detached ui -- there will be no polling events for them anyway
219200
}
220201

221202
parentUI = null;
222-
223-
if (componentDetachListenerRegistration != null) componentDetachListenerRegistration.remove();
224-
if (uiDetachListenerRegistration != null) uiDetachListenerRegistration.remove();
225-
if (pollingListenerRegistration != null) pollingListenerRegistration.remove();
226-
if (beforeLeaveListenerRegistration != null) beforeLeaveListenerRegistration.remove();
227203
}
228204
}
229205

@@ -276,13 +252,5 @@ private void onPollEvent(PollEvent event) {
276252
missedPolls++;
277253
AsyncManager.adjustPollingInterval(parentUI);
278254
}
279-
if (syncCommand != null) {
280-
try {
281-
syncCommand.execute();
282-
} catch (RuntimeException e) {
283-
AsyncManager.handleException(e);
284-
}
285-
remove();
286-
}
287255
}
288256
}

0 commit comments

Comments
 (0)