Coverage Report - org.jbehave.ant.AbstractEmbedderTask
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractEmbedderTask
93%
120/129
72%
13/18
1.268
AbstractEmbedderTask$AntEmbedderMonitor
37%
31/83
12%
1/8
1.268
 
 1  
 package org.jbehave.ant;
 2  
 
 3  
 import java.io.File;
 4  
 import java.io.IOException;
 5  
 import java.net.MalformedURLException;
 6  
 import java.net.URL;
 7  
 import java.util.ArrayList;
 8  
 import java.util.List;
 9  
 import java.util.Properties;
 10  
 import java.util.concurrent.ExecutorService;
 11  
 
 12  
 import org.apache.tools.ant.Task;
 13  
 import org.apache.tools.ant.filters.StringInputStream;
 14  
 import org.jbehave.core.ConfigurableEmbedder;
 15  
 import org.jbehave.core.InjectableEmbedder;
 16  
 import org.jbehave.core.embedder.Embedder;
 17  
 import org.jbehave.core.embedder.EmbedderClassLoader;
 18  
 import org.jbehave.core.embedder.EmbedderControls;
 19  
 import org.jbehave.core.embedder.EmbedderMonitor;
 20  
 import org.jbehave.core.embedder.MetaFilter;
 21  
 import org.jbehave.core.embedder.NullEmbedderMonitor;
 22  
 import org.jbehave.core.embedder.UnmodifiableEmbedderControls;
 23  
 import org.jbehave.core.embedder.executors.ExecutorServiceFactory;
 24  
 import org.jbehave.core.failures.BatchFailures;
 25  
 import org.jbehave.core.io.StoryFinder;
 26  
 import org.jbehave.core.junit.AnnotatedEmbedderRunner;
 27  
 import org.jbehave.core.model.Meta;
 28  
 import org.jbehave.core.model.Scenario;
 29  
 import org.jbehave.core.model.Story;
 30  
 import org.jbehave.core.model.StoryDuration;
 31  
 import org.jbehave.core.model.StoryMaps;
 32  
 import org.jbehave.core.reporters.ReportsCount;
 33  
 
 34  
 import static java.util.Arrays.asList;
 35  
 import static org.apache.tools.ant.Project.MSG_DEBUG;
 36  
 import static org.apache.tools.ant.Project.MSG_INFO;
 37  
 import static org.apache.tools.ant.Project.MSG_WARN;
 38  
 
 39  
 /**
 40  
  * Abstract task that holds all the configuration parameters to specify and load
 41  
  * stories.
 42  
  * 
 43  
  * @author Mauro Talevi
 44  
  */
 45  16
 public abstract class AbstractEmbedderTask extends Task {
 46  
 
 47  
     private static final String TEST_SCOPE = "test";
 48  
 
 49  16
     private String sourceDirectory = "src/main/java";
 50  
 
 51  16
     private String testSourceDirectory = "src/test/java";
 52  
 
 53  16
     private String outputDirectory = "target/classes";
 54  
 
 55  16
     private String testOutputDirectory = "target/test-classes";
 56  
 
 57  
     /**
 58  
      * The scope of the source, either "compile" or "test"
 59  
      */
 60  16
     private String scope = "compile";
 61  
 
 62  
     /**
 63  
      * Include filters, relative to the root source directory determined by the
 64  
      * scope
 65  
      */
 66  16
     private List<String> includes = new ArrayList<String>();
 67  
 
 68  
     /**
 69  
      * Exclude filters, relative to the root source directory determined by the
 70  
      * scope
 71  
      */
 72  16
     private List<String> excludes = new ArrayList<String>();
 73  
 
 74  
     /**
 75  
      * The boolean flag to skip running stories
 76  
      */
 77  16
     private boolean skip = false;
 78  
 
 79  
     /**
 80  
      * The boolean flag to ignore failure in stories
 81  
      */
 82  16
     private boolean ignoreFailureInStories = false;
 83  
 
 84  
     /**
 85  
      * The boolean flag to ignore failure in view
 86  
      */
 87  16
     private boolean ignoreFailureInView = false;
 88  
 
 89  
     /**
 90  
      * The boolean flag to generate view after stories
 91  
      */
 92  16
     private boolean generateViewAfterStories = true;
 93  
 
 94  
     /**
 95  
      * The boolean flag to run in batch mode
 96  
      */
 97  16
     private boolean batch = false;
 98  
 
 99  
     /**
 100  
      * The boolean flag to output failures in verbose mode
 101  
      */
 102  16
     private boolean verboseFailures = false;
 103  
 
 104  
     /**
 105  
      * The boolean flag to output filtering in verbose mode
 106  
      */
 107  16
     private boolean verboseFiltering = false;
 108  
 
 109  
     /**
 110  
      * The story timeout in secs
 111  
      */
 112  16
     long storyTimeoutInSecs = 300;
 113  
     
 114  
     /**
 115  
      * The story timeout in secs by path
 116  
      */
 117  16
     String storyTimeoutInSecsByPath = "";
 118  
 
 119  
     /**
 120  
      * The boolean flag to fail on story timeout
 121  
      */
 122  16
     private boolean failOnStoryTimeout = false;
 123  
 
 124  
     /**
 125  
      * The number of threads
 126  
      */
 127  16
     private int threads = 1;
 128  
 
 129  
     /**
 130  
      * The embedder to run the stories
 131  
      */
 132  16
     private String embedderClass = Embedder.class.getName();
 133  
 
 134  
     /**
 135  
      * The implementation class of the {@link ExecutorServiceFactory}
 136  
      */
 137  
     private String executorsClass;
 138  
 
 139  
     /**
 140  
      * The class that is injected to provide embedder to run the stories.
 141  
      */
 142  
     private String injectableEmbedderClass;
 143  
 
 144  
     /**
 145  
      * The annotated embedder runner class to run the stories
 146  
      * 
 147  
      * @deprecated Obsolete
 148  
      */
 149  16
     String annotatedEmbedderRunnerClass = AnnotatedEmbedderRunner.class.getName();
 150  
 
 151  
     /**
 152  
      * Used to find story paths and class names
 153  
      */
 154  16
     private String storyFinderClass = StoryFinder.class.getName();
 155  
 
 156  
     /**
 157  
      * The meta filters
 158  
      */
 159  16
     private List<String> metaFilters = asList();
 160  
 
 161  
     /**
 162  
      * The system properties
 163  
      */
 164  16
     private Properties systemProperties = new Properties();
 165  
 
 166  
     /**
 167  
      * The classloader
 168  
      */
 169  
     private EmbedderClassLoader classLoader;
 170  
 
 171  
     /**
 172  
      * Determines if the scope of the source directory is "test"
 173  
      * 
 174  
      * @return A boolean <code>true</code> if test scoped
 175  
      */
 176  
     boolean isTestScope() {
 177  14
         return TEST_SCOPE.equals(scope);
 178  
     }
 179  
 
 180  
     String searchDirectory() {
 181  6
         if (isTestScope()) {
 182  1
             return testSourceDirectory;
 183  
         }
 184  5
         return sourceDirectory;
 185  
     }
 186  
 
 187  
     String outputDirectory() {
 188  8
         if (isTestScope()) {
 189  0
             return testOutputDirectory;
 190  
         }
 191  8
         return outputDirectory;
 192  
     }
 193  
 
 194  
     URL codeLocation() {
 195  8
         String outputDirectory = outputDirectory();
 196  
         try {
 197  8
             return outputDirectory != null ? new File(outputDirectory).toURI().toURL() : null;
 198  0
         } catch (MalformedURLException e) {
 199  0
             throw new IllegalArgumentException("Failed to create code location from " + outputDirectory, e);
 200  
         }
 201  
     }
 202  
 
 203  
     /**
 204  
      * Creates the EmbedderClassLoader with the classpath element of the
 205  
      * selected scope
 206  
      * 
 207  
      * @return A EmbedderClassLoader
 208  
      */
 209  
     protected EmbedderClassLoader classLoader() {
 210  8
         if (classLoader == null) {
 211  8
             classLoader = new EmbedderClassLoader(this.getClass().getClassLoader());
 212  
         }
 213  8
         return classLoader;
 214  
     }
 215  
 
 216  
     protected EmbedderMonitor embedderMonitor() {
 217  7
         return new AntEmbedderMonitor();
 218  
     }
 219  
 
 220  
     protected EmbedderControls embedderControls() {
 221  7
         return new UnmodifiableEmbedderControls(new EmbedderControls().doBatch(batch).doSkip(skip)
 222  7
                 .doGenerateViewAfterStories(generateViewAfterStories).doIgnoreFailureInStories(ignoreFailureInStories)
 223  7
                 .doIgnoreFailureInView(ignoreFailureInView).doVerboseFailures(verboseFailures)
 224  7
                 .doVerboseFiltering(verboseFiltering).useStoryTimeoutInSecs(storyTimeoutInSecs)
 225  7
                 .useStoryTimeoutInSecsByPath(storyTimeoutInSecsByPath)
 226  7
                 .doFailOnStoryTimeout(failOnStoryTimeout).useThreads(threads));
 227  
     }
 228  
 
 229  
     /**
 230  
      * Finds story paths, using the {@link #newStoryFinder()}, in the
 231  
      * {@link #searchDirectory()} given specified {@link #includes} and
 232  
      * {@link #excludes}.
 233  
      * 
 234  
      * @return A List of story paths found
 235  
      */
 236  
     protected List<String> storyPaths() {
 237  2
         log("Searching for story paths including " + includes + " and excluding " + excludes, MSG_DEBUG);
 238  2
         List<String> storyPaths = newStoryFinder().findPaths(searchDirectory(), includes, excludes);
 239  2
         log("Found story paths: " + storyPaths, MSG_INFO);
 240  2
         return storyPaths;
 241  
     }
 242  
 
 243  
     /**
 244  
      * Finds class names, using the {@link #newStoryFinder()}, in the
 245  
      * {@link #searchDirectory()} given specified {@link #includes} and
 246  
      * {@link #excludes}.
 247  
      * 
 248  
      * @return A List of class names found
 249  
      */
 250  
     protected List<String> classNames() {
 251  3
         log("Searching for class names including " + includes + " and excluding " + excludes, MSG_DEBUG);
 252  3
         List<String> classNames = newStoryFinder().findClassNames(searchDirectory(), includes, excludes);
 253  3
         log("Found class names : " + classNames, MSG_INFO);
 254  3
         return classNames;
 255  
     }
 256  
 
 257  
     /**
 258  
      * Creates an instance of StoryFinder, using the {@link #storyFinderClass}
 259  
      * 
 260  
      * @return A StoryFinder
 261  
      */
 262  
     protected StoryFinder newStoryFinder() {
 263  6
         return classLoader().newInstance(StoryFinder.class, storyFinderClass);
 264  
     }
 265  
 
 266  
     /**
 267  
      * Creates an instance of Embedder, either using
 268  
      * {@link #injectableEmbedderClass} (if set) or defaulting to
 269  
      * {@link #embedderClass}.
 270  
      * 
 271  
      * @return An Embedder
 272  
      */
 273  
     protected Embedder newEmbedder() {
 274  7
         Embedder embedder = null;
 275  7
         EmbedderClassLoader classLoader = classLoader();
 276  7
         if (injectableEmbedderClass != null) {
 277  1
             embedder = classLoader.newInstance(InjectableEmbedder.class, injectableEmbedderClass).injectedEmbedder();
 278  
         } else {
 279  6
             embedder = classLoader.newInstance(Embedder.class, embedderClass);
 280  
         }
 281  
 
 282  7
         URL codeLocation = codeLocation();
 283  7
         if (codeLocation != null) {
 284  7
             embedder.configuration().storyReporterBuilder().withCodeLocation(codeLocation);
 285  
         }
 286  
 
 287  7
         embedder.useClassLoader(classLoader);
 288  7
         embedder.useEmbedderControls(embedderControls());
 289  7
         if (executorsClass != null) {
 290  1
             ExecutorServiceFactory executorServiceFactory = classLoader.newInstance(ExecutorServiceFactory.class,
 291  
                     executorsClass);
 292  1
             embedder.useExecutorService(executorServiceFactory.create(embedder.embedderControls()));
 293  
         }
 294  7
         embedder.useEmbedderMonitor(embedderMonitor());
 295  7
         if (!metaFilters.isEmpty()) {
 296  0
             embedder.useMetaFilters(metaFilters);
 297  
         }
 298  7
         if (!systemProperties.isEmpty()) {
 299  1
             embedder.useSystemProperties(systemProperties);
 300  
         }
 301  7
         return embedder;
 302  
     }
 303  
 
 304  16
     protected class AntEmbedderMonitor extends NullEmbedderMonitor {
 305  
         public void batchFailed(BatchFailures failures) {
 306  1
             log("Failed to run batch " + failures, MSG_WARN);
 307  1
         }
 308  
 
 309  
         public void beforeOrAfterStoriesFailed() {
 310  0
             log("Failed to run before or after stories steps", MSG_WARN);
 311  0
         }
 312  
 
 313  
         public void embeddableFailed(String name, Throwable cause) {
 314  1
             log("Failed to run embeddable " + name, cause, MSG_WARN);
 315  1
         }
 316  
 
 317  
         public void embeddableNotConfigurable(String name) {
 318  0
             log("Embeddable " + name + " must be an instance of " + ConfigurableEmbedder.class, MSG_WARN);
 319  0
         }
 320  
 
 321  
         public void embeddablesSkipped(List<String> classNames) {
 322  1
             log("Skipped embeddables " + classNames, MSG_INFO);
 323  1
         }
 324  
 
 325  
         public void metaNotAllowed(Meta meta, MetaFilter filter) {
 326  0
             log(meta + " excluded by filter '" + filter.asString() + "'", MSG_DEBUG);
 327  0
         }
 328  
 
 329  
         public void runningEmbeddable(String name) {
 330  1
             log("Running embeddable " + name, MSG_INFO);
 331  1
         }
 332  
 
 333  
         public void storyFailed(String path, Throwable cause) {
 334  1
             log("Failed to run story " + path, cause, MSG_WARN);
 335  1
         }
 336  
 
 337  
         public void storiesSkipped(List<String> storyPaths) {
 338  1
             log("Skipped stories " + storyPaths, MSG_INFO);
 339  1
         }
 340  
 
 341  
         public void storiesNotAllowed(List<Story> stories, MetaFilter filter, boolean verbose) {
 342  0
             StringBuffer sb = new StringBuffer();
 343  0
             sb.append(stories.size() + " stories excluded by filter: " + filter.asString() + "\n");
 344  0
             if (verbose) {
 345  0
                 for (Story story : stories) {
 346  0
                     sb.append(story.getPath()).append("\n");
 347  0
                 }
 348  
             }
 349  0
             log(sb.toString(), MSG_INFO);
 350  0
         }
 351  
         
 352  
             public void scenarioNotAllowed(Scenario scenario, MetaFilter filter) {
 353  0
             StringBuffer sb = new StringBuffer();
 354  0
             sb.append("Scenario "+scenario.getTitle()+" excluded by filter: " + filter.asString() + "\n");
 355  0
             log(sb.toString(), MSG_INFO);
 356  0
             }
 357  
 
 358  
         public void runningStory(String path) {
 359  1
             log("Running story " + path, MSG_INFO);
 360  1
         }
 361  
 
 362  
         public void runningWithAnnotatedEmbedderRunner(String className) {
 363  0
             log("Running with AnnotatedEmbedderRunner '" + className + "'", MSG_INFO);
 364  0
         }
 365  
 
 366  
         public void annotatedInstanceNotOfType(Object annotatedInstance, Class<?> type) {
 367  1
             log("Annotated instance " + annotatedInstance + " not of type " + type, MSG_WARN);
 368  1
         }
 369  
 
 370  
         public void generatingReportsView(File outputDirectory, List<String> formats, Properties viewProperties) {
 371  1
             log("Generating reports view to '" + outputDirectory + "' using formats '" + formats + "'"
 372  
                     + " and view properties '" + viewProperties + "'", MSG_INFO);
 373  1
         }
 374  
 
 375  
         public void reportsViewGenerationFailed(File outputDirectory, List<String> formats, Properties viewProperties,
 376  
                 Throwable cause) {
 377  1
             log("Failed to generate reports view to '" + outputDirectory + "' using formats '" + formats + "'"
 378  
                     + " and view properties '" + viewProperties + "'", cause, MSG_WARN);
 379  1
         }
 380  
 
 381  
         public void reportsViewGenerated(ReportsCount count) {
 382  2
             log("Reports view generated with " + count.getStories() + " stories (of which " + count.getStoriesPending()
 383  1
                     + " pending) containing " + count.getScenarios() + " scenarios (of which "
 384  1
                     + count.getScenariosPending() + " pending)", MSG_INFO);
 385  1
             if (count.getStoriesNotAllowed() > 0 || count.getScenariosNotAllowed() > 0) {
 386  2
                 log("Meta filters excluded " + count.getStoriesNotAllowed() + " stories and  "
 387  1
                         + count.getScenariosNotAllowed() + " scenarios", MSG_INFO);
 388  
             }
 389  1
         }
 390  
 
 391  
         public void reportsViewFailures(ReportsCount count) {
 392  0
             log("Failures in reports view: " + count.getScenariosFailed() + " scenarios failed", MSG_WARN);
 393  0
         }
 394  
 
 395  
         public void reportsViewNotGenerated() {
 396  1
             log("Reports view not generated", MSG_INFO);
 397  1
         }
 398  
 
 399  
         public void mappingStory(String storyPath, List<String> metaFilters) {
 400  0
             log("Mapping story " + storyPath + " with meta filters " + metaFilters, MSG_INFO);
 401  0
         }
 402  
 
 403  
         public void generatingMapsView(File outputDirectory, StoryMaps storyMaps, Properties viewProperties) {
 404  0
             log("Generating maps view to '" + outputDirectory + "' using story maps '" + storyMaps + "'"
 405  
                     + " and view properties '" + viewProperties + "'", MSG_INFO);
 406  0
         }
 407  
 
 408  
         public void mapsViewGenerationFailed(File outputDirectory, StoryMaps storyMaps, Properties viewProperties,
 409  
                 Throwable cause) {
 410  0
             log("Failed to generate maps view to '" + outputDirectory + "' using story maps '" + storyMaps + "'"
 411  
                     + " and view properties '" + viewProperties + "'", cause, MSG_WARN);
 412  0
         }
 413  
 
 414  
         public void generatingNavigatorView(File outputDirectory, Properties viewProperties) {
 415  0
             log("Generating navigator view to '" + outputDirectory + "' using  properties '" + viewProperties + "'",
 416  
                     MSG_INFO);
 417  0
         }
 418  
 
 419  
         public void navigatorViewGenerationFailed(File outputDirectory, Properties viewProperties, Throwable cause) {
 420  0
             log("Failed to generating navigator view to '" + outputDirectory + "' using  properties '" + viewProperties
 421  
                     + "'", cause, MSG_WARN);
 422  0
         }
 423  
 
 424  
         public void navigatorViewNotGenerated() {
 425  0
             log("Navigator view not generated, as the CrossReference has not been declared in the StoryReporterBuilder",
 426  
                     MSG_WARN);
 427  0
         }
 428  
 
 429  
         public void processingSystemProperties(Properties properties) {
 430  0
             log("Processing system properties " + properties, MSG_INFO);
 431  0
         }
 432  
 
 433  
         public void systemPropertySet(String name, String value) {
 434  0
             log("System property '" + name + "' set to '" + value + "'", MSG_INFO);
 435  0
         }
 436  
 
 437  
         public void storyTimeout(Story story, StoryDuration storyDuration) {
 438  0
             log("Story " + story.getPath() + " duration of " + storyDuration.getDurationInSecs()
 439  0
                     + " seconds has exceeded timeout of " + storyDuration.getTimeoutInSecs() + " seconds", MSG_INFO);
 440  0
         }
 441  
 
 442  
         public void usingThreads(int threads) {
 443  0
             log("Using " + threads + " threads", MSG_INFO);
 444  0
         }
 445  
 
 446  
         public void usingExecutorService(ExecutorService executorService) {
 447  0
             log("Using executor service " + executorService, MSG_INFO);
 448  0
         }
 449  
 
 450  
         public void usingControls(EmbedderControls embedderControls) {
 451  0
             log("Using controls " + embedderControls, MSG_INFO);
 452  0
         }
 453  
                 
 454  
         public void invalidTimeoutFormat(String path) {
 455  0
                 log("Failed to set specific story timeout for story " + path + " because 'storyTimeoutInSecsByPath' has incorrect format", MSG_WARN);
 456  0
                 log("'storyTimeoutInSecsByPath' must be a CSV of regex expressions matching story paths. E.g. \"*/long/*.story:5000,*/short/*.story:200\"", MSG_WARN);
 457  0
             }
 458  
         
 459  
             public void usingTimeout(String path, long timeout) {
 460  0
                 log("Using timeout for story " + path + " of "+timeout+" secs.", MSG_INFO);
 461  0
             }
 462  
 
 463  
         @Override
 464  
         public String toString() {
 465  1
             return this.getClass().getSimpleName();
 466  
         } 
 467  
     }
 468  
     
 469  
     // Setters used by Task to inject dependencies
 470  
 
 471  
     public void setSourceDirectory(String sourceDirectory) {
 472  5
         this.sourceDirectory = sourceDirectory;
 473  5
     }
 474  
 
 475  
     public void setTestSourceDirectory(String testSourceDirectory) {
 476  1
         this.testSourceDirectory = testSourceDirectory;
 477  1
     }
 478  
 
 479  
     public void setOutputDirectory(String outputDirectory) {
 480  2
         this.outputDirectory = outputDirectory;
 481  2
     }
 482  
 
 483  
     public void setTestOutputDirectory(String testOutputDirectory) {
 484  1
         this.testOutputDirectory = testOutputDirectory;
 485  1
     }
 486  
 
 487  
     public void setScope(String scope) {
 488  1
         this.scope = scope;
 489  1
     }
 490  
 
 491  
     public void setIncludes(String includesCSV) {
 492  5
         this.includes = asList(includesCSV.split(","));
 493  5
     }
 494  
 
 495  
     public void setExcludes(String excludesCSV) {
 496  5
         this.excludes = asList(excludesCSV.split(","));
 497  5
     }
 498  
 
 499  
     public void setBatch(boolean batch) {
 500  1
         this.batch = batch;
 501  1
     }
 502  
 
 503  
     public void setSkip(boolean skip) {
 504  1
         this.skip = skip;
 505  1
     }
 506  
 
 507  
     public void setIgnoreFailureInStories(boolean ignoreFailureInStories) {
 508  1
         this.ignoreFailureInStories = ignoreFailureInStories;
 509  1
     }
 510  
 
 511  
     public void setIgnoreFailureInView(boolean ignoreFailureInView) {
 512  1
         this.ignoreFailureInView = ignoreFailureInView;
 513  1
     }
 514  
 
 515  
     public void setGenerateViewAfterStories(boolean generateViewAfterStories) {
 516  1
         this.generateViewAfterStories = generateViewAfterStories;
 517  1
     }
 518  
 
 519  
     public void setVerboseFailures(boolean verboseFailures) {
 520  1
         this.verboseFailures = verboseFailures;
 521  1
     }
 522  
 
 523  
     public void setVerboseFiltering(boolean verboseFiltering) {
 524  1
         this.verboseFiltering = verboseFiltering;
 525  1
     }
 526  
 
 527  
     public void setStoryTimeoutInSecs(long storyTimeoutInSecs) {
 528  1
         this.storyTimeoutInSecs = storyTimeoutInSecs;
 529  1
     }
 530  
     
 531  
     public void setStoryTimeoutInSecsByPath(String storyTimeoutInSecsByPath) {
 532  1
         this.storyTimeoutInSecsByPath = storyTimeoutInSecsByPath;
 533  1
     }
 534  
 
 535  
         public void setFailOnStoryTimeout(boolean failOnStoryTimeout) {
 536  1
                 this.failOnStoryTimeout = failOnStoryTimeout;
 537  1
         }
 538  
         
 539  
     public void setThreads(int threads) {
 540  1
         this.threads = threads;
 541  1
     }
 542  
 
 543  
     public void setEmbedderClass(String embedderClass) {
 544  1
         this.embedderClass = embedderClass;
 545  1
     }
 546  
 
 547  
     public void setExecutorsClass(String executorsClass) {
 548  1
         this.executorsClass = executorsClass;
 549  1
     }
 550  
 
 551  
     public void setInjectableEmbedderClass(String injectableEmbedderClass) {
 552  1
         this.injectableEmbedderClass = injectableEmbedderClass;
 553  1
     }
 554  
 
 555  
     public void setAnnotatedEmbedderRunnerClass(String annotatedEmbedderRunnerClass) {
 556  0
         this.annotatedEmbedderRunnerClass = annotatedEmbedderRunnerClass;
 557  0
     }
 558  
 
 559  
     public void setStoryFinderClass(String storyFinderClass) {
 560  1
         this.storyFinderClass = storyFinderClass;
 561  1
     }
 562  
 
 563  
     public void setMetaFilters(String metaFiltersCSV) {
 564  0
         this.metaFilters = asList(metaFiltersCSV.split(","));
 565  0
     }
 566  
 
 567  
     public void setSystemProperties(String systemPropertiesCSV) {
 568  1
         this.systemProperties = loadProperties(systemPropertiesCSV);
 569  1
     }
 570  
 
 571  
     private Properties loadProperties(String systemPropertiesCSV) {
 572  1
         Properties properties = new Properties();
 573  
         try {
 574  1
             properties.load(new StringInputStream(systemPropertiesCSV.replace(",", "\n")));
 575  0
         } catch (IOException e) {
 576  
             // return empty map
 577  1
         }
 578  1
         return properties;
 579  
     }
 580  
 
 581  
 }