/
HangingJobPart.java
308 lines (272 loc) · 9.31 KB
/
HangingJobPart.java
1
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
package org.eclipse.platform.resources;
import static com.xored.q7.quality.mockups.swt.internal.QualityPlatformPlugin.PLUGIN_ID;
import static java.util.Arrays.asList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Spinner;
import com.xored.q7.quality.mockups.issues.BaseMockupPart;
import com.xored.q7.quality.mockups.swt.internal.QualityPlatformPlugin;
/**
* Emulates hanged job with specified parameters.
* Developed for UIJobCollector testing.
* */
public class HangingJobPart extends BaseMockupPart {
interface Function<Argument, Return> {
Return apply(Argument input);
}
private static final IStatus[] STATUSES = new IStatus[] {
new Status(IStatus.OK, PLUGIN_ID, "Job OK"),
new Status(IStatus.INFO, PLUGIN_ID, "Job info"),
new Status(IStatus.WARNING, PLUGIN_ID, "Job warning"),
new Status(IStatus.ERROR, PLUGIN_ID, "Job error")
};
private int count = 0;
private final List<String> activeJobs = Collections.synchronizedList(new ArrayList<String>());
private ListViewer activeJobsViewer;
private static Object getSelected(final ComboViewer combo) {
return ((IStructuredSelection) combo.getSelection()).getFirstElement();
}
@Override
public Control construct(Composite parent) {
GridLayoutFactory.swtDefaults().numColumns(2).applyTo(parent);
Label label = new Label(parent, SWT.NONE);
label.setText("Hang type:");
final ComboViewer hangTypeCombo = createCombo(parent, asList(HangType.values()));
label = new Label(parent, SWT.NONE);
label.setText("Thread type:");
final ComboViewer threadTypeCombo = createCombo(parent, asList(ThreadType.values()));
label = new Label(parent, SWT.NONE);
label.setText("Return status:");
final ComboViewer statusCombo = createCombo(parent, asList(STATUSES));
statusCombo.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
if (element instanceof IStatus)
return ((IStatus) element).getMessage();
return super.getText(element);
}
});
label = new Label(parent, SWT.NONE);
label.setText("Return method:");
final ComboViewer returnPolicyCombo = createCombo(parent, asList(ReturnPolicy.values()));
label = new Label(parent, SWT.NONE);
label.setText("Hang time (ms):");
final Spinner jobHangTimeoutSpinner = createSpinner(parent);
label = new Label(parent, SWT.NONE);
label.setText("Delay (ms):");
final Spinner delaySpinner = createSpinner(parent);
Button startNewJobButton = new Button(parent, SWT.NONE);
startNewJobButton.setText("Start New Job!");
startNewJobButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
super.widgetSelected(e);
HangType hang = (HangType) getSelected(hangTypeCombo);
ThreadType thread = (ThreadType) getSelected(threadTypeCombo);
IStatus status = (IStatus) getSelected(statusCombo);
ReturnPolicy returnPolicy = (ReturnPolicy) getSelected(returnPolicyCombo);
startNewJob(hang, delaySpinner.getSelection(), jobHangTimeoutSpinner.getSelection(), thread, status,
returnPolicy);
}
});
Button terminateAllJobsButton = new Button(parent, SWT.NONE);
terminateAllJobsButton.setText("Terminate All");
terminateAllJobsButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
super.widgetSelected(e);
terminateAll();
}
});
activeJobsViewer = new ListViewer(parent);
activeJobsViewer.setContentProvider(new ArrayContentProvider());
activeJobsViewer.setLabelProvider(new LabelProvider());
activeJobsViewer.setInput(activeJobs);
GridDataFactory.fillDefaults().span(2, 1).grab(true, true).applyTo(activeJobsViewer.getControl());
return parent;
}
private Spinner createSpinner(final Composite container) {
final Spinner spinner = new Spinner(container, SWT.BORDER);
spinner.setMinimum(0);
spinner.setMaximum(180000);
spinner.setSelection(1000);
GridDataFactory.fillDefaults().grab(true, false).applyTo(spinner);
return spinner;
}
private static ComboViewer createCombo(final Composite container, List<?> values) {
ComboViewer combo = new ComboViewer(container);
combo.setContentProvider(new ArrayContentProvider());
combo.setLabelProvider(new LabelProvider());
combo.setInput(values);
combo.setSelection(new StructuredSelection(values.get(0)));
GridDataFactory.fillDefaults().grab(true, false).applyTo(combo.getControl());
return combo;
}
private Runnable activeJobsRefreshRunnable = new Runnable() {
@Override
public void run() {
activeJobsViewer.refresh(true);
while (activeJobsViewer.getControl().getDisplay().readAndDispatch())
;
activeJobsViewer.getControl().redraw();
}
};
private void startNewJob(final HangType hangType, int delay, final int timeout, ThreadType thread,
final IStatus rv, final ReturnPolicy returnPolicy) {
final String name;
synchronized (this) {
name = "Wait type: " + hangType + ", threading: " + thread + ", return: " + rv.getMessage() + ", delay "
+ delay + ", time: " + timeout + ", instance:" + count++;
}
thread.start(delay, new Function<IProgressMonitor, IStatus>() {
@Override
public IStatus apply(IProgressMonitor input) {
try {
activeJobs.add(name);
refresh();
hangType.hang(input, timeout);
} catch (InterruptedException e) {
return new Status(IStatus.WARNING, PLUGIN_ID, "Interrupted");
} finally {
activeJobs.remove(name);
refresh();
}
return returnPolicy.processReturnValue(rv);
}
private void refresh() {
Display.getDefault().syncExec(activeJobsRefreshRunnable);
}
});
}
private void terminateAll() {
Job.getJobManager().cancel(ThreadType.jobGroup);
}
private enum ThreadType {
DIRECT {
@Override
void start(int delay, Function<IProgressMonitor, IStatus> method) {
toRunnable(method).run();
}
},
SYNC_DISPLAY {
@Override
void start(int delay, final Function<IProgressMonitor, IStatus> method) {
Display.getDefault().syncExec(toRunnable(method));
}
},
ASYNC_DISPLAY {
@Override
void start(int delay, Function<IProgressMonitor, IStatus> method) {
Display.getDefault().asyncExec(toRunnable(method));
}
},
TIMER_EXEC {
@Override
void start(int delay, Function<IProgressMonitor, IStatus> method) {
Display.getDefault().timerExec(delay, toRunnable(method));
}
},
JOB {
@Override
void start(int delay, final Function<IProgressMonitor, IStatus> method) {
Job job = new Job(method.getClass().getName()) {
@Override
protected IStatus run(IProgressMonitor monitor) {
return method.apply(monitor);
}
};
job.schedule(delay);
}
};
abstract void start(int delay, Function<IProgressMonitor, IStatus> method);
private final static Object jobGroup = new Object();
}
private static Runnable toRunnable(final Function<IProgressMonitor, IStatus> method) {
return new Runnable() {
@Override
public void run() {
final IStatus status = method.apply(new NullProgressMonitor());
if (!status.isOK()) {
throw new RuntimeException(status.getMessage());
}
}
};
}
private enum ReturnPolicy {
RETURN
{
@Override
IStatus processReturnValue(IStatus status) {
return status;
}
},
LOG {
@Override
IStatus processReturnValue(IStatus status) {
QualityPlatformPlugin.getDefault().getLog().log(status);
return Status.OK_STATUS;
}
},
THROW {
@Override
IStatus processReturnValue(IStatus status) {
throw new RuntimeException(new CoreException(status));
}
};
abstract IStatus processReturnValue(IStatus status);
}
private enum HangType {
LOOP {
@Override
void hang(IProgressMonitor monitor, int timeout) {
Date startTime = new Date();
while (!monitor.isCanceled()) {
Date currentTime = new Date();
if (currentTime.getTime() - startTime.getTime() >= timeout) {
break;
}
}
}
},
THREAD_SLEEP {
@Override
void hang(IProgressMonitor monitor, int timeout) throws InterruptedException {
Thread.sleep(timeout);
}
},
OBJECT_WAIT {
@Override
void hang(IProgressMonitor monitor, int timeout) throws InterruptedException {
Object object = new Object();
synchronized (object) {
object.wait(timeout);
}
}
};
abstract void hang(IProgressMonitor monitor, int timeout) throws InterruptedException;
}
}