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