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