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