1
2
3
4
5
6 package net.kwfgrid.gwui;
7
8 import net.kwfgrid.gworkflowdl.structure.Workflow;
9
10 import org.glassbox.Theme;
11 import org.glassbox.SwingFactory;
12 import org.glassbox.SwingThread;
13 import org.glassbox.gui.*;
14 import org.glassbox.executor.Executor;
15 import org.glassbox.widgets.VisibleExecutor;
16 import org.glassbox.widgets.StatusBarExecutor;
17
18 import javax.swing.*;
19 import java.awt.*;
20 import java.awt.event.ActionEvent;
21
22 import org.apache.log4j.Logger;
23
24 /***
25 Widget to start/stop/pause the Workflow.
26 This widget has the following properties which can be configured in the application's theme:
27 <ul>
28 <li>kwfgrid.WorkflowController.start.icon</li>
29 <li>kwfgrid.WorkflowController.stop.icon</li>
30 <li>kwfgrid.WorkflowController.pause.icon</li>
31 <li>kwfgrid.WorkflowController.task.background.color</li>
32 <li>kwfgrid.WorkflowController.task.text.color</li>
33 <li>kwfgrid.WorkflowController.task.insets</li>
34 <li>kwfgrid.WorkflowController.task.font</li>
35 <li>kwfgrid.Toolbar.button.background.color</li>
36 <li>kwfgrid.Toolbar.button.border.color</li>
37 <li>kwfgrid.Toolbar.button.insets</li>
38 <li>kwfgrid.Toolbar.background.color</li>
39 <li>kwfgrid.Toolbar.border.color</li>VisibleExecutor;
40 <li>kwfgrid.Toolbar.insets</li>
41 <li>kwfgrid.Toolbar.layout-gap.size</li>
42 </ul>
43 */
44 public class WorkflowController extends AbstractMember implements VisibleMember {
45 public static final String IDENTIFIER = "net.kwfgrid.gwui.WorkflowController";
46
47 private class StartAction extends AbstractAction {
48 public StartAction() {
49 super(null, START_ICON);
50 }
51
52 public void actionPerformed(ActionEvent e) {
53 setPerformingAction(true);
54 _executor.execute(new StartTask(getWorkflowID()));
55 }
56 }
57
58 private class ResumeAction extends AbstractAction {
59 public ResumeAction() {
60 super(null, START_ICON);
61 }
62
63 public void actionPerformed(ActionEvent e) {
64 setPerformingAction(true);
65 _executor.execute(new ResumeTask(getWorkflowID()));
66 }
67 }
68
69 private class AbortAction extends AbstractAction {
70 public AbortAction() {
71 super(null, ABORT_ICON);
72 }
73
74 public void actionPerformed(ActionEvent e) {
75 setPerformingAction(true);
76 _executor.execute(new AbortTask(getWorkflowID()));
77 }
78 }
79
80 private class SuspendAction extends AbstractAction {
81 public SuspendAction() {
82 super(null, SUSPEND_ICON);
83 }
84
85 public void actionPerformed(ActionEvent e) {
86 setPerformingAction(true);
87 _executor.execute(new SuspendTask(getWorkflowID()));
88 }
89 }
90
91 private class StartTask implements VisibleExecutor.VisibleTask, StatusBarExecutor.Task {
92 private JComponent _view = SwingFactory.createLabel(getMessage(), TASK_THEME_PREFIX);
93 private String _wfid;
94
95 public StartTask(String wfid) {
96 _wfid = wfid;
97 }
98
99 public JComponent getView() {
100 return _view;
101 }
102
103 public String getMessage() {
104 return "Starting workflow ...";
105 }
106
107 public void run() {
108 try {
109 _gwes.start(_wfid);
110 } catch (Exception x) {
111 logger.warn("Could not start workflow.", x);
112 JDialog e = SwingFactory2.createErrorDialog("Error", "Workflow could not be started.", x);
113 e.show();
114 }
115 setPerformingAction(false);
116 }
117 }
118
119 private class ResumeTask implements VisibleExecutor.VisibleTask, StatusBarExecutor.Task {
120 private JComponent _view = SwingFactory.createLabel(getMessage(), TASK_THEME_PREFIX);
121 private String _wfid;
122
123 public ResumeTask(String wfid) {
124 _wfid = wfid;
125 }
126
127 public JComponent getView() {
128 return _view;
129 }
130
131 public String getMessage() {
132 return "Resuming workflow ...";
133 }
134
135 public void run() {
136 try {
137 _gwes.resume(_wfid);
138 } catch (Exception x) {
139 logger.warn("Could not start workflow.", x);
140 JDialog e = SwingFactory2.createErrorDialog("Error", "Workflow could not be resumed.", x);
141 e.show();
142 }
143 setPerformingAction(false);
144 }
145 }
146
147 private class AbortTask implements VisibleExecutor.VisibleTask, StatusBarExecutor.Task {
148 private JComponent _view = SwingFactory.createLabel(getMessage(), TASK_THEME_PREFIX);
149 private String _wfid;
150
151 public AbortTask(String wfid) {
152 _wfid = wfid;
153 }
154
155
156 public JComponent getView() {
157 return _view;
158 }
159
160 public String getMessage() {
161 return "Aborting workflow ...";
162 }
163
164 public void run() {
165 try {
166 _gwes.abort(_wfid);
167 } catch (Exception x) {
168 logger.warn("Could not start workflow.", x);
169 JDialog e = SwingFactory2.createErrorDialog("Error", "Workflow could not be aborted.", x);
170 e.show();
171 }
172 setPerformingAction(false);
173 }
174 }
175
176 private class SuspendTask implements VisibleExecutor.VisibleTask, StatusBarExecutor.Task {
177 private JComponent _view = SwingFactory.createLabel(getMessage(), TASK_THEME_PREFIX);
178 private String _wfid;
179
180 public SuspendTask(String wfid) {
181 _wfid = wfid;
182 }
183
184
185 public JComponent getView() {
186 return _view;
187 }
188
189 public String getMessage() {
190 return "Suspending workflow ...";
191 }
192
193 public void run() {
194 try {
195 _gwes.suspend(_wfid);
196 } catch (Exception x) {
197 logger.warn("Could not start workflow.", x);
198 JDialog e = SwingFactory2.createErrorDialog("Error", "Workflow could not be suspended.", x);
199 e.show();
200 }
201 setPerformingAction(false);
202 }
203 }
204
205
206 private Runnable UPDATE_STATE = new Runnable() {
207 public void run() { updateState(); }
208 };
209
210 /*** The prefix of the theme configuration of the visible tasks. */
211 private static final String TASK_THEME_PREFIX = "kwfgrid.WorkflowController.task";
212
213 private static final String BUTTON_THEME_PREFIX = "kwfgrid.Toolbar.button";
214 private static final String PANEL_THEME_PREFIX = "kwfgrid.Toolbar";
215 private static final String START_ICON_KEY = "kwfgrid.WorkflowController.start.icon";
216 private static final String ABORT_ICON_KEY = "kwfgrid.WorkflowController.stop.icon";
217 private static final String SUSPEND_ICON_KEY = "kwfgrid.WorkflowController.pause.icon";
218 private static final String LAYOUT_GAP_KEY = "kwfgrid.Toolbar.layout-gap.size";
219 private static final Icon START_ICON = Theme.getIcon(START_ICON_KEY);
220 private static final Icon ABORT_ICON = Theme.getIcon(ABORT_ICON_KEY);
221 private static final Icon SUSPEND_ICON = Theme.getIcon(SUSPEND_ICON_KEY);
222 private static final Dimension LAYOUT_GAP = Theme.getSize(LAYOUT_GAP_KEY);
223
224 private static final Logger logger = Logger.getLogger(WorkflowController.class);
225
226 private Executor _executor;
227 private net.kwfgrid.gwes.GWES _gwes;
228 private boolean _performingaction;
229
230 private JPanel _view;
231 private JButton _bstart, _babort, _bsuspend;
232
233 public WorkflowController(Executor executor) throws Exception {
234 _executor = executor;
235 _gwes = GWUI.getInstance().getGWES();
236 _view = null;
237 _performingaction = false;
238 }
239
240 protected String getWorkflowID() {
241 Workflow wf = (Workflow)getGroup().getProperty(WorkflowGroup.ACTIVE_WORKFLOW_DOCUMENT_KEY);
242 return wf!=null?wf.getID():null;
243 }
244
245 private void setPerformingAction(boolean perf) {
246 _performingaction = perf;
247 SwingThread.invokeAndWaitSilently(UPDATE_STATE);
248 }
249
250 private void updateState() {
251 logger.debug("updateState()");
252
253 if (getGroup()!=null && _view!=null) {
254 Object modalmember = getGroup().getProperty(VisibleGroup.MODAL_MEMBER_KEY);
255 Object status = getGroup().getProperty(WorkflowGroup.WORKFLOW_STATUS_KEY);
256 Object appstatus = getGroup().getProperty(Group.APPLICATION_STATUS_KEY);
257 String workflowid = getWorkflowID();
258
259 if (status==null) status = WorkflowGroup.STATUS_UNDEFINED;
260
261 if (status.equals(WorkflowGroup.STATUS_UNDEFINED) ||
262 status.equals(WorkflowGroup.STATUS_TERMINATED) ||
263 status.equals(WorkflowGroup.STATUS_COMPLETED) ||
264 Group.EXITING.equals(appstatus) ||
265 workflowid==null) {
266 _view.setVisible(false);
267 } else {
268 _view.setVisible(true);
269 if (modalmember!=null ||
270 _gwes==null ||
271 _performingaction) {
272 _bstart.setEnabled(false);
273 _babort.setEnabled(false);
274 _bsuspend.setEnabled(false);
275 } else if (status.equals(WorkflowGroup.STATUS_INITIATED)) {
276 _bstart.setEnabled(true);
277 _babort.setEnabled(true);
278 _bsuspend.setEnabled(false);
279 _bstart.setAction(new StartAction());
280 } else if (status.equals(WorkflowGroup.STATUS_RUNNING) ||
281 status.equals(WorkflowGroup.STATUS_ACTIVE)) {
282 _bstart.setEnabled(false);
283 _babort.setEnabled(true);
284 _bsuspend.setEnabled(true);
285 } else if (status.equals(WorkflowGroup.STATUS_SUSPENDED)) {
286 _bstart.setEnabled(true);
287 _babort.setEnabled(true);
288 _bsuspend.setEnabled(false);
289 _bstart.setAction(new ResumeAction());
290 }
291 }
292 }
293
294 logger.debug("updateState.exit");
295 }
296
297 public JComponent getView() {
298 if (_view==null) {
299 _bstart = SwingFactory.createButton(BUTTON_THEME_PREFIX, START_ICON);
300 _bstart.setAction(new StartAction());
301 _babort = SwingFactory.createButton(BUTTON_THEME_PREFIX, ABORT_ICON);
302 _babort.setAction(new AbortAction());
303 _bsuspend = SwingFactory.createButton(BUTTON_THEME_PREFIX, SUSPEND_ICON);
304 _bsuspend.setAction(new SuspendAction());
305 _view = SwingFactory.createPanel(PANEL_THEME_PREFIX);
306 _view.setLayout(new FlowLayout(FlowLayout.LEFT, LAYOUT_GAP.width, LAYOUT_GAP.height));
307 _view.add(_bstart);
308 _view.add(_bsuspend);
309 _view.add(_babort);
310 _view.setSize(_view.getLayout().preferredLayoutSize(_view));
311 _view.validate();
312 updateState();
313 }
314 return _view;
315 }
316
317 public String getIdentifier() {
318 return IDENTIFIER;
319 }
320
321 public void setGroup(Group group) {
322 super.setGroup(group);
323 updateState();
324 }
325
326 public void groupPropertyChanged(String name, Object oldvalue, Object newvalue) {
327 logger.debug("groupPropertyChanged("+name+", "+oldvalue+", "+newvalue+")");
328
329 if (name.equals(Group.APPLICATION_STATUS_KEY)) {
330 if (Group.EXITING.equals(newvalue)) {
331 if (_view!=null) _view.setVisible(false);
332 }
333 } else if (name.equals(VisibleGroup.MODAL_MEMBER_KEY)) {
334 updateState();
335 } else if (name.equals(WorkflowGroup.ACTIVE_WORKFLOW_DOCUMENT_KEY)) {
336 updateState();
337 } else if (name.equals(WorkflowGroup.WORKFLOW_STATUS_KEY)) {
338 updateState();
339 }
340
341 logger.debug("groupPropertyChanged.exit");
342 }
343 }