1 package fr.ifremer.quadrige3.ui.swing.action;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import fr.ifremer.quadrige3.core.exception.QuadrigeTechnicalException;
27 import fr.ifremer.quadrige3.core.config.QuadrigeCoreConfiguration;
28 import fr.ifremer.quadrige3.ui.swing.ApplicationUI;
29 import fr.ifremer.quadrige3.ui.swing.ApplicationUIContext;
30 import fr.ifremer.quadrige3.ui.swing.AbstractUIHandler;
31 import fr.ifremer.quadrige3.ui.swing.model.ProgressionUIModel;
32 import org.jdesktop.beans.AbstractBean;
33 import org.nuiton.i18n.I18n;
34
35 import javax.swing.AbstractAction;
36 import javax.swing.Icon;
37 import javax.swing.SwingWorker;
38 import java.awt.event.ActionEvent;
39 import java.util.concurrent.ExecutionException;
40 import java.util.concurrent.ThreadPoolExecutor;
41
42
43
44
45
46
47
48
49
50 public abstract class AbstractWorkerAction<M extends AbstractBean, UI extends ApplicationUI<M, ?>, H extends AbstractUIHandler<M, UI>>
51 extends AbstractAction {
52
53 protected final H handler;
54
55 private Worker worker;
56
57 private final ThreadPoolExecutor executor;
58
59 private final Object lock = new Object();
60
61 private boolean wait;
62
63 private Exception reportedException;
64
65
66
67
68
69
70 public abstract boolean initAction();
71
72
73
74
75
76
77 public abstract void doAction() throws Exception;
78
79
80
81
82 public abstract void doneAction();
83
84
85
86
87
88
89 public abstract void failedAction(Throwable ex);
90
91
92
93
94 public abstract void disposeAction();
95
96
97
98
99
100
101 public AbstractWorkerAction(H handler) {
102
103 super();
104 this.handler = handler;
105
106
107 executor = ActionFactory.createSingleThreadExecutor(ActionFactory.ExecutionMode.UNIQUE);
108 }
109
110
111
112
113
114
115 public H getHandler() {
116 return handler;
117 }
118
119
120
121
122
123
124 public UI getUI() {
125 return handler.getUI();
126 }
127
128
129
130
131
132
133 public M getModel() {
134 return handler.getModel();
135 }
136
137
138
139
140
141
142 public QuadrigeCoreConfiguration getConfig() {
143 return handler.getConfig();
144 }
145
146
147
148
149
150
151 public ApplicationUIContext getContext() {
152 return handler.getContext();
153 }
154
155
156 @Override
157 public boolean isEnabled() {
158 return super.isEnabled() && (worker == null || worker.isDone());
159 }
160
161 public boolean isRunning() {
162 return executor.getActiveCount() > 0;
163 }
164
165
166
167
168
169
170 public String getActionDescription() {
171 return (String) getValue(SHORT_DESCRIPTION);
172 }
173
174
175
176
177
178
179 public void setActionDescription(String actionDescription) {
180 putValue(SHORT_DESCRIPTION, actionDescription);
181 }
182
183
184
185
186
187
188 public void setActionIcon(Icon actionIcon) {
189 putValue(SMALL_ICON, actionIcon);
190 putValue(LARGE_ICON_KEY, actionIcon);
191 }
192
193
194
195
196
197
198 public void setActionKey(String actionKey) {
199 putValue(ACTION_COMMAND_KEY, actionKey);
200 }
201
202
203
204
205
206
207 public void setActionName(String actionName) {
208 putValue(NAME, actionName);
209 }
210
211
212
213
214
215
216 public void setActionMnemonic(int key) {
217 putValue(MNEMONIC_KEY, key);
218 }
219
220
221
222
223 public void execute() {
224 run();
225 }
226
227
228
229
230
231
232 public void executeAndWait() throws Exception {
233 wait = true;
234 run();
235 lock();
236 if (reportedException != null) {
237 throw reportedException;
238 }
239 }
240
241 private void run() {
242
243 boolean doWork;
244
245 try {
246 doWork = initAction();
247 } catch (Exception ex) {
248 disposeAction();
249 unlock();
250 throw new QuadrigeTechnicalException(I18n.t("quadrige3.error.prepare.action", getActionDescription()), ex);
251 }
252
253 if (doWork) {
254
255 try {
256
257
258 worker = new Worker();
259 executor.execute(worker);
260
261 } catch (Exception ex) {
262 disposeAction();
263 throw new QuadrigeTechnicalException(I18n.t("quadrige3.error.execute.action", getActionDescription()), ex);
264 }
265
266 }
267 else {
268
269 disposeAction();
270 unlock();
271
272 }
273 }
274
275
276 @Override
277 public void actionPerformed(ActionEvent e) {
278
279
280 run();
281
282 }
283
284
285
286
287 protected void lock() {
288 if (wait) {
289 synchronized (lock) {
290 try {
291 lock.wait();
292 } catch (InterruptedException ex) {
293 throw new QuadrigeTechnicalException(I18n.t("quadrige3.error.execute.wait.action", getActionDescription()), ex);
294 } finally {
295 wait = false;
296 }
297 }
298 }
299 }
300
301
302
303
304 protected void unlock() {
305 if (wait) {
306 synchronized (lock) {
307 lock.notifyAll();
308 }
309 }
310 }
311
312
313
314
315
316
317 public boolean isWait() {
318 return wait;
319 }
320
321
322
323
324
325
326 public void setReportedException(Exception reportedException) {
327 this.reportedException = reportedException;
328 }
329
330 private class Worker extends SwingWorker<Void, ProgressionUIModel> {
331
332 public Worker() {
333 }
334
335 @Override
336 protected Void doInBackground() throws Exception {
337
338 doAction();
339
340 return null;
341 }
342
343 @Override
344 protected void done() {
345
346 try {
347 try {
348 get();
349 doneAction();
350 } catch (InterruptedException ex) {
351 if (wait) {
352 throw new QuadrigeTechnicalException(ex);
353 }
354 else {
355 failedAction(ex);
356 }
357 } catch (ExecutionException ex) {
358 Throwable cause = ex.getCause();
359 if (wait) {
360 if (cause != null && cause instanceof Exception) {
361 setReportedException((Exception) cause);
362 }
363 else {
364 setReportedException(ex);
365 }
366 }
367 else {
368 failedAction(cause);
369 }
370 }
371 } finally {
372 disposeAction();
373 unlock();
374
375 }
376
377 }
378
379 }
380
381 }