Skip to content

Commit 27eab6e

Browse files
committed
#1 Add AsyncManager.setExecutorService()
1 parent aa9896d commit 27eab6e

File tree

6 files changed

+207
-162
lines changed

6 files changed

+207
-162
lines changed

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,17 @@ termination. For polling mode it also supports
7272
dynamic polling intervals: i.e. you can have 5 polls per second in the
7373
first second and then throttle it to send poll requests once per second:
7474
```java
75-
AsyncManager.setPollingIntervals(200, 200, 200, 200, 200, 1000);
75+
AsyncManager.getInstance().setPollingIntervals(200, 200, 200, 200, 200, 1000);
7676
```
7777

7878
It is also possible to set custom exception handler if you
7979
want some custom logging or exception reporting:
8080
```java
81-
AsyncManager.setExceptionHandler(exception -> ...);
81+
AsyncManager.getInstance().setExceptionHandler(exception -> ...);
8282
```
8383

8484
Note: By default all worker threads are started by `ThreadPoolExecutor` which defaults
85-
to pool size of 25 threads. If you want to increase it or change other settings, you can access instance of executor with
86-
`AsyncManager.getExecutor()`.
85+
to pool size of 25 threads. You can change that with `AsyncManager.getInstance().setExecutorService()`.
8786

8887
## Installing with Maven
8988

@@ -98,7 +97,7 @@ to pool size of 25 threads. If you want to increase it or change other settings,
9897
<dependency>
9998
<groupId>org.vaadin.helper</groupId>
10099
<artifactId>async-manager</artifactId>
101-
<version>1.0.0-alpha1</version>
100+
<version>1.0.0-alpha2</version>
102101
</dependency>
103102
```
104103

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
<groupId>org.vaadin.helper</groupId>
77
<artifactId>async-manager</artifactId>
8-
<version>1.0.0-alpha1</version>
8+
<version>1.0.0-alpha2</version>
99
<name>Async Manager</name>
1010
<description>Async Manager for Vaadin Flow</description>
1111

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
*
88
* @author Artem Godin
99
* @see AsyncManager#register(Component, AsyncAction)
10-
* @see AsyncManager#register(Component, boolean, AsyncAction)
1110
*/
1211
@FunctionalInterface
1312
public interface AsyncAction {

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

Lines changed: 126 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@
44
import com.vaadin.flow.component.Component;
55
import com.vaadin.flow.component.UI;
66

7-
import java.io.Serializable;
87
import java.util.*;
9-
import java.util.concurrent.LinkedBlockingQueue;
10-
import java.util.concurrent.ThreadPoolExecutor;
11-
import java.util.concurrent.TimeUnit;
8+
import java.util.concurrent.ExecutorService;
9+
import java.util.concurrent.Executors;
1210
import java.util.function.Consumer;
1311

1412
/**
@@ -31,56 +29,125 @@
3129
* of interrupting tasks when the view is detached from UI or if the UI leaves current view.
3230
* <p>
3331
* Initial configuration of AsyncManager can be done using {@link AsyncManager#setExceptionHandler(Consumer)},
34-
* {@link AsyncManager#setPollingIntervals(int...)} and {@link AsyncManager#getExecutor()} static methods.
32+
* {@link AsyncManager#setPollingIntervals(int...)} and {@link AsyncManager#setExecutorService(ExecutorService)} static methods.
3533
*
3634
* @author Artem Godin
3735
* @see AsyncTask
3836
* @see AsyncAction
3937
*/
40-
public class AsyncManager implements Serializable {
38+
public class AsyncManager {
39+
//--- Defaults
40+
41+
/**
42+
* Default pool size (25 threads)
43+
*/
44+
private static final int DEFAULT_POOL_SIZE = 25;
45+
/**
46+
* Default polling intervals (200 ms)
47+
*/
48+
private static final int[] DEFAULT_POLLING_INTERVALS = {200};
49+
50+
//--- The one and only instance of AsyncManager
51+
52+
/**
53+
* Instance of AsyncManager
54+
*/
55+
private static AsyncManager instance;
56+
57+
//-- Private fields
58+
59+
/**
60+
* List of all registered {@link AsyncTask} per component instance
61+
*/
62+
private Map<UI, Set<AsyncTask>> asyncTasks = Collections.synchronizedMap(new WeakHashMap<>());
63+
/**
64+
* Exception handler
65+
*/
66+
private Consumer<Exception> exceptionHandler = AsyncManager::logException;
67+
/**
68+
* Instance of {@link ExecutorService} used for asynchronous tasks
69+
*/
70+
private ExecutorService executorService = Executors.newFixedThreadPool(DEFAULT_POOL_SIZE);
71+
/**
72+
* Polling intervals
73+
*/
74+
private int[] pollingIntervals = DEFAULT_POLLING_INTERVALS;
75+
76+
private AsyncManager() { // Not directly instantiatable
77+
}
78+
79+
//--- Static methods
80+
81+
/**
82+
* Get instance of AsyncManager
83+
*
84+
* @return Instance of AsyncManager
85+
*/
86+
public static synchronized AsyncManager getInstance() {
87+
if (instance == null) {
88+
instance = new AsyncManager();
89+
}
90+
return instance;
91+
}
4192

4293
/**
4394
* Register and start a new deferred action. Action are started immediately in a separate thread and do not hold
4495
* {@code UI} or {@code VaadinSession} locks.
96+
* <p>
97+
* Shorthand for {@code AsyncManager.getInstance().registerAsync(component, action)}
4598
*
4699
* @param component Component, where the action needs to be performed, typically your view
47100
* @param action Action
48101
* @return {@link AsyncTask}, associated with this action
49102
*/
50103
public static AsyncTask register(Component component, AsyncAction action) {
51-
Objects.requireNonNull(component);
52-
53-
AsyncTask asyncTask = new AsyncTask();
54-
UI ui = component.getUI().orElse(null);
55-
if (ui != null) {
56-
asyncTask.register(ui, component, action);
57-
} else {
58-
component.addAttachListener(attachEvent -> {
59-
attachEvent.unregisterListener();
60-
asyncTask.register(attachEvent.getUI(), component, action);
61-
});
62-
}
63-
return asyncTask;
104+
return getInstance().registerAsync(component, action);
64105
}
65106

66107
/**
67-
* Get a {@link ThreadPoolExecutor} used for asynchronous task execution. This can be used to
68-
* adjust thread pool size.
108+
* Default exception handler that simply logs the exception
69109
*
70-
* @return static instance of {@link ThreadPoolExecutor}
110+
* @param e Exception to handle
71111
*/
72-
public static ThreadPoolExecutor getExecutor() {
73-
return executor;
112+
private static void logException(Throwable e) {
113+
LoggerFactory.getLogger(AsyncManager.class.getName()).warn(e.getMessage(), e);
74114
}
75115

116+
//--- Getters and setters
117+
76118
/**
77119
* Set custom exception handler for exceptions thrown in async tasks if you need custom logging or
78120
* reporting
79121
*
80122
* @param handler Exception handler to set
81123
*/
82-
public static void setExceptionHandler(Consumer<Exception> handler) {
83-
AsyncManager.exceptionHandler = handler;
124+
public void setExceptionHandler(Consumer<Exception> handler) {
125+
exceptionHandler = handler;
126+
}
127+
128+
/**
129+
* Get a {@link ExecutorService} used for asynchronous task execution.
130+
*
131+
* @return static instance of {@link ExecutorService}
132+
*/
133+
ExecutorService getExecutorService() {
134+
return executorService;
135+
}
136+
137+
/**
138+
* Set {@link ExecutorService} to be used for asynchronous task execution.
139+
*/
140+
public void setExecutorService(ExecutorService executorService) {
141+
this.executorService = executorService;
142+
}
143+
144+
/**
145+
* Get polling intervals
146+
*
147+
* @return polling intervals in milliseconds
148+
*/
149+
int[] getPollingIntervals() {
150+
return pollingIntervals;
84151
}
85152

86153
/**
@@ -94,63 +161,46 @@ public static void setExceptionHandler(Consumer<Exception> handler) {
94161
*
95162
* @param milliseconds Polling intervals in milliseconds
96163
*/
97-
public static void setPollingIntervals(int... milliseconds) {
164+
public void setPollingIntervals(int... milliseconds) {
98165
if (milliseconds.length == 0) {
99-
AsyncManager.pollingIntervals = DEFAULT_POLLING_INTERVALS;
166+
pollingIntervals = DEFAULT_POLLING_INTERVALS;
100167
}
101-
AsyncManager.pollingIntervals = milliseconds;
102-
}
103-
104-
private AsyncManager() { // Not directly instantiatable
168+
pollingIntervals = milliseconds;
105169
}
106170

107171
/**
108-
* Default pool size (25 threads)
109-
*/
110-
private static final int DEFAULT_POOL_SIZE = 25;
111-
112-
/**
113-
* Default polling intervals (200 ms)
114-
*/
115-
private static final int[] DEFAULT_POLLING_INTERVALS = {200};
116-
117-
/**
118-
* Instance of {@link ThreadPoolExecutor} used for asynchronous tasks
119-
*/
120-
private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(DEFAULT_POOL_SIZE, DEFAULT_POOL_SIZE,
121-
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
122-
123-
/**
124-
* List of all registered {@link AsyncTask} per component instance
125-
*/
126-
private static Map<UI, Set<AsyncTask>> asyncTasks = Collections.synchronizedMap(new WeakHashMap<>());
127-
128-
/**
129-
* Exception handler
130-
*/
131-
private static Consumer<Exception> exceptionHandler = AsyncManager::logException;
132-
133-
/**
134-
* Polling intervals
135-
*/
136-
private static int[] pollingIntervals = DEFAULT_POLLING_INTERVALS;
137-
138-
/**
139-
* Default exception handler that simply logs the exception
172+
* Register and start a new deferred action. Action are started immediately in a separate thread and do not hold
173+
* {@code UI} or {@code VaadinSession} locks.
140174
*
141-
* @param e Exception to handle
175+
* @param component Component, where the action needs to be performed, typically your view
176+
* @param action Action
177+
* @return {@link AsyncTask}, associated with this action
142178
*/
143-
private static void logException(Throwable e) {
144-
LoggerFactory.getLogger(AsyncManager.class.getName()).warn(e.getMessage(), e);
179+
public AsyncTask registerAsync(Component component, AsyncAction action) {
180+
Objects.requireNonNull(component);
181+
182+
AsyncTask asyncTask = new AsyncTask(this);
183+
UI ui = component.getUI().orElse(null);
184+
if (ui != null) {
185+
asyncTask.register(ui, component, action);
186+
} else {
187+
component.addAttachListener(attachEvent -> {
188+
attachEvent.unregisterListener();
189+
asyncTask.register(attachEvent.getUI(), component, action);
190+
});
191+
}
192+
return asyncTask;
145193
}
146194

195+
//--- Implementation
196+
147197
/**
148198
* Get list of active asynchronous tasks for specified component
149199
*
150200
* @param ui Owning UI
151201
* @return Set of {@link AsyncTask}
152202
*/
153-
private static Set<AsyncTask> getAsyncTasks(UI ui) {
203+
private Set<AsyncTask> getAsyncTasks(UI ui) {
154204
return asyncTasks.computeIfAbsent(ui, parentComponent -> Collections.synchronizedSet(new HashSet<>()));
155205
}
156206

@@ -160,8 +210,8 @@ private static Set<AsyncTask> getAsyncTasks(UI ui) {
160210
* @param ui Owning UI
161211
* @param task Task
162212
*/
163-
static void addAsyncTask(UI ui, AsyncTask task) {
164-
AsyncManager.getAsyncTasks(ui).add(task);
213+
void addAsyncTask(UI ui, AsyncTask task) {
214+
getAsyncTasks(ui).add(task);
165215
}
166216

167217
/**
@@ -170,17 +220,17 @@ static void addAsyncTask(UI ui, AsyncTask task) {
170220
* @param ui Owning UI
171221
* @param task Task
172222
*/
173-
static void removeAsyncTask(UI ui, AsyncTask task) {
174-
AsyncManager.getAsyncTasks(ui).remove(task);
223+
void removeAsyncTask(UI ui, AsyncTask task) {
224+
getAsyncTasks(ui).remove(task);
175225
}
176226

177227
/**
178228
* Adjust polling interval for specified component.
179229
*
180230
* @param ui UI, associated with current task
181231
*/
182-
static void adjustPollingInterval(UI ui) {
183-
int newInterval = AsyncManager.getAsyncTasks(ui).stream()
232+
void adjustPollingInterval(UI ui) {
233+
int newInterval = getAsyncTasks(ui).stream()
184234
.map(AsyncTask::getPollingInterval)
185235
.sorted()
186236
.findFirst().orElse(Integer.MAX_VALUE);
@@ -200,16 +250,8 @@ static void adjustPollingInterval(UI ui) {
200250
*
201251
* @param e Exception to handle
202252
*/
203-
static void handleException(Exception e) {
204-
AsyncManager.exceptionHandler.accept(e);
253+
void handleException(Exception e) {
254+
exceptionHandler.accept(e);
205255
}
206256

207-
/**
208-
* Get polling intervals
209-
*
210-
* @return polling intervals in milliseconds
211-
*/
212-
static int[] getPollingIntervals() {
213-
return pollingIntervals;
214-
}
215257
}

0 commit comments

Comments
 (0)