1 | |
package org.jbehave.core.reporters; |
2 | |
|
3 | |
import java.lang.reflect.InvocationTargetException; |
4 | |
import java.lang.reflect.Method; |
5 | |
import java.util.ArrayList; |
6 | |
import java.util.List; |
7 | |
import java.util.Map; |
8 | |
|
9 | |
import org.jbehave.core.model.ExamplesTable; |
10 | |
import org.jbehave.core.model.GivenStories; |
11 | |
import org.jbehave.core.model.Lifecycle; |
12 | |
import org.jbehave.core.model.Meta; |
13 | |
import org.jbehave.core.model.Narrative; |
14 | |
import org.jbehave.core.model.OutcomesTable; |
15 | |
import org.jbehave.core.model.Scenario; |
16 | |
import org.jbehave.core.model.Story; |
17 | |
import org.jbehave.core.model.StoryDuration; |
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
|
23 | |
|
24 | |
public class ConcurrentStoryReporter implements StoryReporter { |
25 | |
|
26 | |
private static Method storyCancelled; |
27 | |
private static Method storyNotAllowed; |
28 | |
private static Method beforeStory; |
29 | |
private static Method afterStory; |
30 | |
private static Method narrative; |
31 | |
private static Method lifecycle; |
32 | |
private static Method scenarioNotAllowed; |
33 | |
private static Method beforeScenario; |
34 | |
private static Method scenarioMeta; |
35 | |
private static Method afterScenario; |
36 | |
private static Method givenStories; |
37 | |
private static Method givenStoriesPaths; |
38 | |
private static Method beforeExamples; |
39 | |
private static Method example; |
40 | |
private static Method afterExamples; |
41 | |
private static Method beforeStep; |
42 | |
private static Method successful; |
43 | |
private static Method ignorable; |
44 | |
private static Method pending; |
45 | |
private static Method notPerformed; |
46 | |
private static Method failed; |
47 | |
private static Method failedOutcomes; |
48 | |
private static Method dryRun; |
49 | |
private static Method pendingMethods; |
50 | |
private static Method restarted; |
51 | |
|
52 | |
static { |
53 | |
try { |
54 | 1 | storyCancelled = StoryReporter.class.getMethod("storyCancelled", Story.class, StoryDuration.class); |
55 | 1 | storyNotAllowed = StoryReporter.class.getMethod("storyNotAllowed", Story.class, String.class); |
56 | 1 | beforeStory = StoryReporter.class.getMethod("beforeStory", Story.class, Boolean.TYPE); |
57 | 1 | afterStory = StoryReporter.class.getMethod("afterStory", Boolean.TYPE); |
58 | 1 | narrative = StoryReporter.class.getMethod("narrative", Narrative.class); |
59 | 1 | lifecycle = StoryReporter.class.getMethod("lifecyle", Lifecycle.class); |
60 | 1 | scenarioNotAllowed = StoryReporter.class.getMethod("scenarioNotAllowed", Scenario.class, String.class); |
61 | 1 | beforeScenario = StoryReporter.class.getMethod("beforeScenario", String.class); |
62 | 1 | scenarioMeta = StoryReporter.class.getMethod("scenarioMeta", Meta.class); |
63 | 1 | afterScenario = StoryReporter.class.getMethod("afterScenario"); |
64 | 1 | givenStories = StoryReporter.class.getMethod("givenStories", GivenStories.class); |
65 | 1 | givenStoriesPaths = StoryReporter.class.getMethod("givenStories", List.class); |
66 | 1 | beforeExamples = StoryReporter.class.getMethod("beforeExamples", List.class, ExamplesTable.class); |
67 | 1 | example = StoryReporter.class.getMethod("example", Map.class); |
68 | 1 | afterExamples = StoryReporter.class.getMethod("afterExamples"); |
69 | 1 | beforeStep = StoryReporter.class.getMethod("beforeStep", String.class); |
70 | 1 | successful = StoryReporter.class.getMethod("successful", String.class); |
71 | 1 | ignorable = StoryReporter.class.getMethod("ignorable", String.class); |
72 | 1 | pending = StoryReporter.class.getMethod("pending", String.class); |
73 | 1 | notPerformed = StoryReporter.class.getMethod("notPerformed", String.class); |
74 | 1 | failed = StoryReporter.class.getMethod("failed", String.class, Throwable.class); |
75 | 1 | failedOutcomes = StoryReporter.class.getMethod("failedOutcomes", String.class, OutcomesTable.class); |
76 | 1 | dryRun = StoryReporter.class.getMethod("dryRun"); |
77 | 1 | pendingMethods = StoryReporter.class.getMethod("pendingMethods", List.class); |
78 | 1 | restarted = StoryReporter.class.getMethod("restarted", String.class, Throwable.class); |
79 | 0 | } catch (NoSuchMethodException e) { |
80 | 0 | throw new RuntimeException(e); |
81 | 1 | } |
82 | 1 | } |
83 | |
|
84 | 19 | private List<DelayedMethod> delayedMethods = new ArrayList<DelayedMethod>(); |
85 | |
private final StoryReporter crossReferencing; |
86 | |
private final StoryReporter delegate; |
87 | |
private final boolean multiThreading; |
88 | 19 | private boolean invoked = false; |
89 | |
|
90 | 19 | public ConcurrentStoryReporter(StoryReporter crossReferencing, StoryReporter delegate, boolean multiThreading) { |
91 | 19 | this.crossReferencing = crossReferencing; |
92 | 19 | this.multiThreading = multiThreading; |
93 | 19 | this.delegate = delegate; |
94 | 19 | } |
95 | |
|
96 | |
public void storyNotAllowed(Story story, String filter) { |
97 | 0 | crossReferencing.storyNotAllowed(story, filter); |
98 | 0 | if (multiThreading) { |
99 | 0 | delayedMethods.add(new DelayedMethod(storyNotAllowed, story, filter)); |
100 | |
} else { |
101 | 0 | delegate.storyNotAllowed(story, filter); |
102 | |
} |
103 | 0 | } |
104 | |
|
105 | |
public void beforeStory(Story story, boolean givenStory) { |
106 | 7 | crossReferencing.beforeStory(story, givenStory); |
107 | 7 | if (multiThreading) { |
108 | 0 | delayedMethods.add(new DelayedMethod(beforeStory, story, givenStory)); |
109 | |
} else { |
110 | 7 | delegate.beforeStory(story, givenStory); |
111 | |
} |
112 | 7 | } |
113 | |
|
114 | |
public void afterStory(boolean givenStory) { |
115 | 7 | crossReferencing.afterStory(givenStory); |
116 | 7 | if (multiThreading) { |
117 | 0 | delayedMethods.add(new DelayedMethod(afterStory, givenStory)); |
118 | |
} else { |
119 | 7 | delegate.afterStory(givenStory); |
120 | |
} |
121 | 7 | } |
122 | |
|
123 | |
public void narrative(Narrative aNarrative) { |
124 | 5 | crossReferencing.narrative(aNarrative); |
125 | 5 | if (multiThreading) { |
126 | 0 | delayedMethods.add(new DelayedMethod(narrative, aNarrative)); |
127 | |
} else { |
128 | 5 | delegate.narrative(aNarrative); |
129 | |
} |
130 | 5 | } |
131 | |
|
132 | |
public void lifecyle(Lifecycle aLifecycle) { |
133 | 2 | crossReferencing.lifecyle(aLifecycle); |
134 | 2 | if (multiThreading) { |
135 | 0 | delayedMethods.add(new DelayedMethod(lifecycle, aLifecycle)); |
136 | |
} else { |
137 | 2 | delegate.lifecyle(aLifecycle); |
138 | |
} |
139 | 2 | } |
140 | |
|
141 | |
public void scenarioNotAllowed(Scenario scenario, String filter) { |
142 | 0 | crossReferencing.scenarioNotAllowed(scenario, filter); |
143 | 0 | if (multiThreading) { |
144 | 0 | delayedMethods.add(new DelayedMethod(scenarioNotAllowed, scenario, filter)); |
145 | |
} else { |
146 | 0 | delegate.scenarioNotAllowed(scenario, filter); |
147 | |
} |
148 | 0 | } |
149 | |
|
150 | |
public void beforeScenario(String scenarioTitle) { |
151 | 8 | crossReferencing.beforeScenario(scenarioTitle); |
152 | 8 | if (multiThreading) { |
153 | 0 | delayedMethods.add(new DelayedMethod(beforeScenario, scenarioTitle)); |
154 | |
} else { |
155 | 8 | delegate.beforeScenario(scenarioTitle); |
156 | |
} |
157 | 8 | } |
158 | |
|
159 | |
public void scenarioMeta(Meta meta) { |
160 | 2 | crossReferencing.scenarioMeta(meta); |
161 | 2 | if (multiThreading) { |
162 | 0 | delayedMethods.add(new DelayedMethod(scenarioMeta, meta)); |
163 | |
} else { |
164 | 2 | delegate.scenarioMeta(meta); |
165 | |
} |
166 | 2 | } |
167 | |
|
168 | |
public void afterScenario() { |
169 | 8 | crossReferencing.afterScenario(); |
170 | 8 | if (multiThreading) { |
171 | 0 | delayedMethods.add(new DelayedMethod(afterScenario)); |
172 | |
} else { |
173 | 8 | delegate.afterScenario(); |
174 | |
} |
175 | 8 | } |
176 | |
|
177 | |
public void givenStories(GivenStories stories) { |
178 | 0 | crossReferencing.givenStories(stories); |
179 | 0 | if (multiThreading) { |
180 | 0 | delayedMethods.add(new DelayedMethod(givenStories, stories)); |
181 | |
} else { |
182 | 0 | delegate.givenStories(stories); |
183 | |
} |
184 | 0 | } |
185 | |
|
186 | |
public void givenStories(List<String> storyPaths) { |
187 | 3 | crossReferencing.givenStories(storyPaths); |
188 | 3 | if (multiThreading) { |
189 | 0 | delayedMethods.add(new DelayedMethod(givenStoriesPaths, storyPaths)); |
190 | |
} else { |
191 | 3 | delegate.givenStories(storyPaths); |
192 | |
} |
193 | 3 | } |
194 | |
|
195 | |
public void beforeExamples(List<String> steps, ExamplesTable table) { |
196 | 3 | crossReferencing.beforeExamples(steps, table); |
197 | 3 | if (multiThreading) { |
198 | 0 | delayedMethods.add(new DelayedMethod(beforeExamples, steps, table)); |
199 | |
} else { |
200 | 3 | delegate.beforeExamples(steps, table); |
201 | |
} |
202 | 3 | } |
203 | |
|
204 | |
public void example(Map<String, String> tableRow) { |
205 | 6 | crossReferencing.example(tableRow); |
206 | 6 | if (multiThreading) { |
207 | 0 | delayedMethods.add(new DelayedMethod(example, tableRow)); |
208 | |
} else { |
209 | 6 | delegate.example(tableRow); |
210 | |
} |
211 | 6 | } |
212 | |
|
213 | |
public void afterExamples() { |
214 | 3 | crossReferencing.afterExamples(); |
215 | 3 | if (multiThreading) { |
216 | 0 | delayedMethods.add(new DelayedMethod(afterExamples)); |
217 | |
} else { |
218 | 3 | delegate.afterExamples(); |
219 | |
} |
220 | 3 | } |
221 | |
|
222 | |
public void beforeStep(String step) { |
223 | 1 | crossReferencing.beforeStep(step); |
224 | 1 | if (multiThreading) { |
225 | 0 | delayedMethods.add(new DelayedMethod(beforeStep, step)); |
226 | |
} else { |
227 | 1 | delegate.beforeStep(step); |
228 | |
} |
229 | 1 | } |
230 | |
|
231 | |
public void successful(String step) { |
232 | 33 | crossReferencing.successful(step); |
233 | 33 | if (multiThreading) { |
234 | 0 | delayedMethods.add(new DelayedMethod(successful, step)); |
235 | |
} else { |
236 | 33 | delegate.successful(step); |
237 | |
} |
238 | 33 | } |
239 | |
|
240 | |
public void ignorable(String step) { |
241 | 3 | crossReferencing.ignorable(step); |
242 | 3 | if (multiThreading) { |
243 | 0 | delayedMethods.add(new DelayedMethod(ignorable, step)); |
244 | |
} else { |
245 | 3 | delegate.ignorable(step); |
246 | |
} |
247 | 3 | } |
248 | |
|
249 | |
public void pending(String step) { |
250 | 6 | crossReferencing.pending(step); |
251 | 6 | if (multiThreading) { |
252 | 0 | delayedMethods.add(new DelayedMethod(pending, step)); |
253 | |
} else { |
254 | 6 | delegate.pending(step); |
255 | |
} |
256 | 6 | } |
257 | |
|
258 | |
public void notPerformed(String step) { |
259 | 3 | crossReferencing.notPerformed(step); |
260 | 3 | if (multiThreading) { |
261 | 0 | delayedMethods.add(new DelayedMethod(notPerformed, step)); |
262 | |
} else { |
263 | 3 | delegate.notPerformed(step); |
264 | |
} |
265 | 3 | } |
266 | |
|
267 | |
public void failed(String step, Throwable cause) { |
268 | 2 | crossReferencing.failed(step, cause); |
269 | 2 | if (multiThreading) { |
270 | 0 | delayedMethods.add(new DelayedMethod(failed, step, cause)); |
271 | |
} else { |
272 | 2 | delegate.failed(step, cause); |
273 | |
} |
274 | 2 | } |
275 | |
|
276 | |
public void failedOutcomes(String step, OutcomesTable table) { |
277 | 3 | crossReferencing.failedOutcomes(step, table); |
278 | 3 | if (multiThreading) { |
279 | 0 | delayedMethods.add(new DelayedMethod(failedOutcomes, step, table)); |
280 | |
} else { |
281 | 3 | delegate.failedOutcomes(step, table); |
282 | |
} |
283 | 3 | } |
284 | |
|
285 | |
public void dryRun() { |
286 | 3 | crossReferencing.dryRun(); |
287 | 3 | if (multiThreading) { |
288 | 0 | delayedMethods.add(new DelayedMethod(dryRun)); |
289 | |
} else { |
290 | 3 | delegate.dryRun(); |
291 | |
} |
292 | 3 | } |
293 | |
|
294 | |
public void pendingMethods(List<String> methods) { |
295 | 3 | crossReferencing.pendingMethods(methods); |
296 | 3 | if (multiThreading) { |
297 | 0 | delayedMethods.add(new DelayedMethod(pendingMethods, methods)); |
298 | |
} else { |
299 | 3 | delegate.pendingMethods(methods); |
300 | |
} |
301 | |
|
302 | 3 | } |
303 | |
|
304 | |
public void restarted(String step, Throwable cause) { |
305 | 3 | crossReferencing.restarted(step, cause); |
306 | 3 | if (multiThreading) { |
307 | 0 | delayedMethods.add(new DelayedMethod(restarted, step, cause)); |
308 | |
} else { |
309 | 3 | delegate.restarted(step, cause); |
310 | |
} |
311 | 3 | } |
312 | |
|
313 | |
public void storyCancelled(Story story, StoryDuration storyDuration) { |
314 | 4 | crossReferencing.storyCancelled(story, storyDuration); |
315 | 4 | if (multiThreading) { |
316 | 0 | delayedMethods.add(new DelayedMethod(storyCancelled, story, storyDuration)); |
317 | |
} else { |
318 | 4 | delegate.storyCancelled(story, storyDuration); |
319 | |
} |
320 | 4 | } |
321 | |
|
322 | |
public StoryReporter getDelegate() { |
323 | 6 | return delegate; |
324 | |
} |
325 | |
|
326 | |
public void invokeDelayed() { |
327 | 7 | if ( !multiThreading ){ |
328 | 7 | return; |
329 | |
} |
330 | 0 | if (invoked) { |
331 | 0 | throw new RuntimeException("Delayed methods already invoked"); |
332 | |
} |
333 | 0 | synchronized (delegate) { |
334 | 0 | for (DelayedMethod delayed : delayedMethods) { |
335 | 0 | delayed.invoke(delegate); |
336 | 0 | } |
337 | 0 | } |
338 | 0 | invoked = true; |
339 | 0 | } |
340 | |
|
341 | |
public static class DelayedMethod { |
342 | |
private Method method; |
343 | |
private Object[] args; |
344 | |
|
345 | 0 | public DelayedMethod(Method method, Object... args) { |
346 | 0 | this.method = method; |
347 | 0 | this.args = args; |
348 | 0 | } |
349 | |
|
350 | |
public void invoke(StoryReporter delegate) { |
351 | |
try { |
352 | 0 | method.invoke(delegate, args); |
353 | 0 | } catch (IllegalAccessException e) { |
354 | 0 | throw new RuntimeException(e); |
355 | 0 | } catch (InvocationTargetException e) { |
356 | 0 | throw new RuntimeException(e); |
357 | 0 | } catch (IllegalArgumentException e) { |
358 | 0 | throw new RuntimeException("" + method, e); |
359 | 0 | } |
360 | 0 | } |
361 | |
} |
362 | |
|
363 | |
} |