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