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