Coverage Report - org.jbehave.core.reporters.ConcurrentStoryReporter
 
Classes in this File Line Coverage Branch Coverage Complexity
ConcurrentStoryReporter
68%
101/148
37%
18/48
2.231
ConcurrentStoryReporter$DelayedMethod
0%
0/13
N/A
2.231
 
 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  
  * When running a multithreading mode, reports cannot be written concurrently but should 
 19  
  * be delayed and invoked only at the end of a story, ensuring synchronization on the delegate
 20  
  * responsible for the reporting.
 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  
 }