4
4
import com .vaadin .flow .component .Component ;
5
5
import com .vaadin .flow .component .UI ;
6
6
7
- import java .io .Serializable ;
8
7
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 ;
12
10
import java .util .function .Consumer ;
13
11
14
12
/**
31
29
* of interrupting tasks when the view is detached from UI or if the UI leaves current view.
32
30
* <p>
33
31
* 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.
35
33
*
36
34
* @author Artem Godin
37
35
* @see AsyncTask
38
36
* @see AsyncAction
39
37
*/
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
+ }
41
92
42
93
/**
43
94
* Register and start a new deferred action. Action are started immediately in a separate thread and do not hold
44
95
* {@code UI} or {@code VaadinSession} locks.
96
+ * <p>
97
+ * Shorthand for {@code AsyncManager.getInstance().registerAsync(component, action)}
45
98
*
46
99
* @param component Component, where the action needs to be performed, typically your view
47
100
* @param action Action
48
101
* @return {@link AsyncTask}, associated with this action
49
102
*/
50
103
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 );
64
105
}
65
106
66
107
/**
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
69
109
*
70
- * @return static instance of {@link ThreadPoolExecutor}
110
+ * @param e Exception to handle
71
111
*/
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 ) ;
74
114
}
75
115
116
+ //--- Getters and setters
117
+
76
118
/**
77
119
* Set custom exception handler for exceptions thrown in async tasks if you need custom logging or
78
120
* reporting
79
121
*
80
122
* @param handler Exception handler to set
81
123
*/
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 ;
84
151
}
85
152
86
153
/**
@@ -94,63 +161,46 @@ public static void setExceptionHandler(Consumer<Exception> handler) {
94
161
*
95
162
* @param milliseconds Polling intervals in milliseconds
96
163
*/
97
- public static void setPollingIntervals (int ... milliseconds ) {
164
+ public void setPollingIntervals (int ... milliseconds ) {
98
165
if (milliseconds .length == 0 ) {
99
- AsyncManager . pollingIntervals = DEFAULT_POLLING_INTERVALS ;
166
+ pollingIntervals = DEFAULT_POLLING_INTERVALS ;
100
167
}
101
- AsyncManager .pollingIntervals = milliseconds ;
102
- }
103
-
104
- private AsyncManager () { // Not directly instantiatable
168
+ pollingIntervals = milliseconds ;
105
169
}
106
170
107
171
/**
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.
140
174
*
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
142
178
*/
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 ;
145
193
}
146
194
195
+ //--- Implementation
196
+
147
197
/**
148
198
* Get list of active asynchronous tasks for specified component
149
199
*
150
200
* @param ui Owning UI
151
201
* @return Set of {@link AsyncTask}
152
202
*/
153
- private static Set <AsyncTask > getAsyncTasks (UI ui ) {
203
+ private Set <AsyncTask > getAsyncTasks (UI ui ) {
154
204
return asyncTasks .computeIfAbsent (ui , parentComponent -> Collections .synchronizedSet (new HashSet <>()));
155
205
}
156
206
@@ -160,8 +210,8 @@ private static Set<AsyncTask> getAsyncTasks(UI ui) {
160
210
* @param ui Owning UI
161
211
* @param task Task
162
212
*/
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 );
165
215
}
166
216
167
217
/**
@@ -170,17 +220,17 @@ static void addAsyncTask(UI ui, AsyncTask task) {
170
220
* @param ui Owning UI
171
221
* @param task Task
172
222
*/
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 );
175
225
}
176
226
177
227
/**
178
228
* Adjust polling interval for specified component.
179
229
*
180
230
* @param ui UI, associated with current task
181
231
*/
182
- static void adjustPollingInterval (UI ui ) {
183
- int newInterval = AsyncManager . getAsyncTasks (ui ).stream ()
232
+ void adjustPollingInterval (UI ui ) {
233
+ int newInterval = getAsyncTasks (ui ).stream ()
184
234
.map (AsyncTask ::getPollingInterval )
185
235
.sorted ()
186
236
.findFirst ().orElse (Integer .MAX_VALUE );
@@ -200,16 +250,8 @@ static void adjustPollingInterval(UI ui) {
200
250
*
201
251
* @param e Exception to handle
202
252
*/
203
- static void handleException (Exception e ) {
204
- AsyncManager . exceptionHandler .accept (e );
253
+ void handleException (Exception e ) {
254
+ exceptionHandler .accept (e );
205
255
}
206
256
207
- /**
208
- * Get polling intervals
209
- *
210
- * @return polling intervals in milliseconds
211
- */
212
- static int [] getPollingIntervals () {
213
- return pollingIntervals ;
214
- }
215
257
}
0 commit comments