Coverage Report - org.jbehave.core.configuration.AnnotationBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
AnnotationBuilder
100%
86/86
100%
18/18
1.944
AnnotationBuilder$InstantiationFailed
100%
4/4
N/A
1.944
 
 1  
 package org.jbehave.core.configuration;
 2  
 
 3  
 import java.util.ArrayList;
 4  
 import java.util.List;
 5  
 
 6  
 import org.jbehave.core.ConfigurableEmbedder;
 7  
 import org.jbehave.core.Embeddable;
 8  
 import org.jbehave.core.annotations.Configure;
 9  
 import org.jbehave.core.annotations.UsingEmbedder;
 10  
 import org.jbehave.core.annotations.UsingSteps;
 11  
 import org.jbehave.core.embedder.Embedder;
 12  
 import org.jbehave.core.embedder.StoryControls;
 13  
 import org.jbehave.core.failures.FailureStrategy;
 14  
 import org.jbehave.core.failures.PendingStepStrategy;
 15  
 import org.jbehave.core.io.StoryLoader;
 16  
 import org.jbehave.core.io.StoryPathResolver;
 17  
 import org.jbehave.core.parsers.StepPatternParser;
 18  
 import org.jbehave.core.parsers.StoryParser;
 19  
 import org.jbehave.core.reporters.StepdocReporter;
 20  
 import org.jbehave.core.reporters.StoryReporter;
 21  
 import org.jbehave.core.reporters.StoryReporterBuilder;
 22  
 import org.jbehave.core.reporters.ViewGenerator;
 23  
 import org.jbehave.core.steps.CandidateSteps;
 24  
 import org.jbehave.core.steps.InjectableStepsFactory;
 25  
 import org.jbehave.core.steps.InstanceStepsFactory;
 26  
 import org.jbehave.core.steps.ParameterConverters;
 27  
 import org.jbehave.core.steps.ParameterConverters.ParameterConverter;
 28  
 import org.jbehave.core.steps.StepCollector;
 29  
 import org.jbehave.core.steps.StepFinder;
 30  
 import org.jbehave.core.steps.StepMonitor;
 31  
 
 32  
 import com.thoughtworks.paranamer.Paranamer;
 33  
 
 34  
 /**
 35  
  * Allows the building of {@link Configuration}, {@link CandidateSteps} and
 36  
  * {@link Embedder} from an annotated class.
 37  
  * 
 38  
  * @author Cristiano GaviĆ£o
 39  
  * @author Mauro Talevi
 40  
  */
 41  
 public class AnnotationBuilder {
 42  
 
 43  
     private final AnnotationMonitor annotationMonitor;
 44  
 
 45  
     private final Class<?> annotatedClass;
 46  
     private final AnnotationFinder finder;
 47  
 
 48  
     public AnnotationBuilder(Class<?> annotatedClass) {
 49  14
         this(annotatedClass, new PrintStreamAnnotationMonitor());
 50  14
     }
 51  
 
 52  14
     public AnnotationBuilder(Class<?> annotatedClass, AnnotationMonitor annotationMonitor) {
 53  14
         this.annotationMonitor = annotationMonitor;
 54  14
         this.annotatedClass = annotatedClass;
 55  14
         this.finder = new AnnotationFinder(annotatedClass);
 56  14
     }
 57  
 
 58  
     public Class<?> annotatedClass() {
 59  1
         return annotatedClass;
 60  
     }
 61  
 
 62  
     /**
 63  
      * Builds a Configuration instance based on annotation {@link Configure}
 64  
      * found in the annotated object instance
 65  
      * 
 66  
      * @return A Configuration instance
 67  
      */
 68  
     public Configuration buildConfiguration() throws AnnotationRequired {
 69  
 
 70  12
         Configuration configuration = new MostUsefulConfiguration();
 71  
 
 72  12
         if (!finder.isAnnotationPresent(Configure.class)) {
 73  
             // not using annotation configuration, default to most useful
 74  
             // configuration
 75  3
             return configuration;
 76  
         }
 77  
 
 78  9
         configuration.useKeywords(configurationElement(finder, "keywords", Keywords.class));
 79  9
         configuration.useFailureStrategy(configurationElement(finder, "failureStrategy", FailureStrategy.class));
 80  9
         configuration.usePendingStepStrategy(configurationElement(finder, "pendingStepStrategy",
 81  
                 PendingStepStrategy.class));
 82  9
         configuration.useParanamer(configurationElement(finder, "paranamer", Paranamer.class));
 83  9
         configuration.useStoryControls(configurationElement(finder, "storyControls", StoryControls.class));
 84  9
         configuration.useStepCollector(configurationElement(finder, "stepCollector", StepCollector.class));
 85  9
         configuration.useStepdocReporter(configurationElement(finder, "stepdocReporter", StepdocReporter.class));
 86  9
         configuration.useStepFinder(configurationElement(finder, "stepFinder", StepFinder.class));
 87  9
         configuration.useStepMonitor(configurationElement(finder, "stepMonitor", StepMonitor.class));
 88  9
         configuration.useStepPatternParser(configurationElement(finder, "stepPatternParser", StepPatternParser.class));
 89  9
         configuration.useStoryLoader(configurationElement(finder, "storyLoader", StoryLoader.class));
 90  9
         configuration.useStoryParser(configurationElement(finder, "storyParser", StoryParser.class));
 91  9
         configuration.useStoryPathResolver(configurationElement(finder, "storyPathResolver", StoryPathResolver.class));
 92  9
         configuration
 93  
                 .useDefaultStoryReporter(configurationElement(finder, "defaultStoryReporter", StoryReporter.class));
 94  9
         configuration.useStoryReporterBuilder(configurationElement(finder, "storyReporterBuilder",
 95  
                 StoryReporterBuilder.class));
 96  9
         configuration.useViewGenerator(configurationElement(finder, "viewGenerator", ViewGenerator.class));
 97  9
         configuration.useParameterConverters(parameterConverters(finder));
 98  9
         return configuration;
 99  
     }
 100  
 
 101  
     /**
 102  
      * Builds CandidateSteps using annotation {@link UsingSteps} found in the
 103  
      * annotated object instance and using the configuration build by
 104  
      * {@link #buildConfiguration()}
 105  
      * 
 106  
      * @return A List of CandidateSteps instances
 107  
      */
 108  
     public List<CandidateSteps> buildCandidateSteps() {
 109  6
         return buildCandidateSteps(buildConfiguration());
 110  
     }
 111  
 
 112  
     /**
 113  
      * Builds CandidateSteps using annotation {@link UsingSteps} found in the
 114  
      * annotated object instance and the configuration provided
 115  
      * 
 116  
      * @param configuration
 117  
      *            the Configuration
 118  
      * @return A List of CandidateSteps instances
 119  
      */
 120  
     public List<CandidateSteps> buildCandidateSteps(Configuration configuration) {
 121  12
         List<Object> stepsInstances = new ArrayList<Object>();
 122  12
         InjectableStepsFactory factory = null;
 123  12
         if (finder.isAnnotationPresent(UsingSteps.class)) {
 124  8
             List<Class<Object>> stepsClasses = finder.getAnnotatedClasses(UsingSteps.class, Object.class, "instances");
 125  8
             for (Class<Object> stepsClass : stepsClasses) {
 126  11
                 stepsInstances.add(instanceOf(Object.class, stepsClass));
 127  
             }
 128  7
             factory = new InstanceStepsFactory(configuration, stepsInstances);
 129  7
         } else {
 130  4
             annotationMonitor.annotationNotFound(UsingSteps.class, annotatedClass);
 131  
         }
 132  
 
 133  11
         if (factory == null) {
 134  4
             factory = new InstanceStepsFactory(configuration);
 135  
         }
 136  11
         return factory.createCandidateSteps();
 137  
     }
 138  
 
 139  
     @SuppressWarnings("unchecked")
 140  
     public Embedder buildEmbedder() {
 141  7
         if (!finder.isAnnotationPresent(UsingEmbedder.class)) {
 142  1
             return new Embedder();
 143  
         }
 144  
 
 145  6
         boolean batch = control(finder, "batch");
 146  6
         boolean skip = control(finder, "skip");
 147  6
         boolean generateViewAfterStories = control(finder, "generateViewAfterStories");
 148  6
         boolean ignoreFailureInStories = control(finder, "ignoreFailureInStories");
 149  6
         boolean ignoreFailureInView = control(finder, "ignoreFailureInView");
 150  6
         Configuration configuration = buildConfiguration();
 151  6
         List<CandidateSteps> candidateSteps = buildCandidateSteps(configuration);
 152  
 
 153  6
         Embedder embedder = instanceOf(Embedder.class, (Class<? extends Embedder>)finder.getAnnotatedValue(UsingEmbedder.class, Class.class,
 154  
                 "embedder"));
 155  6
         embedder.embedderControls().doBatch(batch).doSkip(skip).doGenerateViewAfterStories(generateViewAfterStories)
 156  
                 .doIgnoreFailureInStories(ignoreFailureInStories).doIgnoreFailureInView(ignoreFailureInView);
 157  6
         embedder.useConfiguration(configuration);
 158  6
         embedder.useCandidateSteps(candidateSteps);
 159  6
         List<String> metaFilters = finder.getAnnotatedValues(UsingEmbedder.class, String.class, "metaFilters");
 160  6
         if ( !metaFilters.isEmpty() ){
 161  2
             embedder.useMetaFilters(metaFilters);
 162  
         }
 163  6
         return embedder;
 164  
     }
 165  
 
 166  
     private boolean control(AnnotationFinder finder, String name) {
 167  30
         return finder.getAnnotatedValue(UsingEmbedder.class, Boolean.class, name);
 168  
     }
 169  
 
 170  
     private <T> T configurationElement(AnnotationFinder finder, String name, Class<T> type) {
 171  144
         Class<T> implementation = elementImplementation(finder, name);
 172  144
         return instanceOf(type, implementation);
 173  
     }
 174  
 
 175  
     @SuppressWarnings("unchecked")
 176  
     private <T> Class<T> elementImplementation(AnnotationFinder finder, String name) {
 177  144
         return (Class<T>) finder.getAnnotatedValue(Configure.class, Class.class, name);
 178  
     }
 179  
 
 180  
     protected ParameterConverters parameterConverters(AnnotationFinder annotationFinder) {
 181  9
         List<ParameterConverter> converters = new ArrayList<ParameterConverter>();
 182  9
         for (Class<ParameterConverter> converterClass : annotationFinder.getAnnotatedClasses(Configure.class,
 183  
                 ParameterConverter.class, "parameterConverters")) {
 184  3
             converters.add(instanceOf(ParameterConverter.class, converterClass));
 185  
         }
 186  9
         return new ParameterConverters().addConverters(converters);
 187  
     }
 188  
 
 189  
     protected <T, V extends T> T instanceOf(Class<T> type, Class<V> ofClass) {
 190  
         try {
 191  164
             return (T) ofClass.newInstance();
 192  1
         } catch (Exception e) {
 193  1
             annotationMonitor.elementCreationFailed(ofClass, e);
 194  1
             throw new InstantiationFailed(ofClass, type, e);
 195  
         }
 196  
     }
 197  
 
 198  
     protected AnnotationMonitor annotationMonitor() {
 199  1
         return annotationMonitor;
 200  
     }
 201  
 
 202  
     protected AnnotationFinder annotationFinder() {
 203  1
         return finder;
 204  
     }
 205  
 
 206  
     public Object embeddableInstance() {
 207  6
         return injectEmbedder(buildEmbedder(), annotatedClass);
 208  
     }
 209  
 
 210  
     protected Object injectEmbedder(Embedder embedder, Class<?> annotatedClass) {
 211  
         try {
 212  6
             Object instance = annotatedClass.newInstance();
 213  5
             if (instance instanceof Embeddable) {
 214  4
                 Embeddable embeddable = (Embeddable) instance;
 215  4
                 embeddable.useEmbedder(embedder);
 216  
             }
 217  5
             if (instance instanceof ConfigurableEmbedder) {
 218  1
                 ConfigurableEmbedder configurableEmbedder = (ConfigurableEmbedder) instance;
 219  1
                 configurableEmbedder.useConfiguration(embedder.configuration());
 220  1
                 configurableEmbedder.addSteps(embedder.candidateSteps());
 221  
             }
 222  5
             return instance;
 223  1
         } catch (Exception e) {
 224  1
             annotationMonitor.elementCreationFailed(annotatedClass, e);
 225  1
             throw new InstantiationFailed(annotatedClass, e);
 226  
         }
 227  
     }
 228  
 
 229  
     @SuppressWarnings("serial")
 230  
     public static class InstantiationFailed extends RuntimeException {
 231  
 
 232  
         public InstantiationFailed(Class<?> ofClass, Class<?> type, Throwable cause) {
 233  1
             super("Failed to instantiate class " + ofClass + " of type " + type, cause);
 234  1
         }
 235  
 
 236  
         public InstantiationFailed(Class<?> ofClass, Throwable cause) {
 237  1
             super("Failed to instantiate class " + ofClass, cause);
 238  1
         }
 239  
 
 240  
     }
 241  
 
 242  
 }