package com.gfk.senbot.documenter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; import org.jdom.Document; import org.jdom.Element; import org.jdom.output.XMLOutputter; import org.reflections.Reflections; import org.reflections.util.ConfigurationBuilder; import com.gfk.senbot.framework.context.SenBotContext; import cucumber.api.java.en.When; import cucumber.runtime.java.StepDefAnnotation; @Mojo(name = "document", defaultPhase = LifecyclePhase.PACKAGE) public class SenBotDocumenter extends AbstractMojo { @Component private MavenProject project; private Map<String, StepDef> availableStepDefs = new HashMap<String, StepDef>(); public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, IOException { SenBotDocumenter senBotDocumenter = new SenBotDocumenter(); senBotDocumenter.generateDocumentation(); } public void generateDocumentation() throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, IOException { ConfigurationBuilder cb = new ConfigurationBuilder(); cb.addUrls(SenBotContext.class.getProtectionDomain().getCodeSource().getLocation()); cb.addUrls(When.class.getProtectionDomain().getCodeSource().getLocation()); Reflections cucumberStepDefReflections = new Reflections(cb); Set<Class<?>> allCucumberStepMethodAnnotations = cucumberStepDefReflections.getTypesAnnotatedWith(StepDefAnnotation.class); for(Class parentClass : allCucumberStepMethodAnnotations) { if(parentClass.toString().contains("cucumber.api.java")) { //it's a given/when/then/and/but annotation continue; } else { Method[] allMethods = parentClass.getMethods(); for(Method m : allMethods) { Annotation[] annotations = m.getAnnotations(); for(Annotation an : annotations) { if(an.toString().contains("cucumber.api.java")) { Method valueFetcher = an.getClass().getMethod("value"); Object invoke = valueFetcher.invoke(an); if(invoke instanceof String) { StepDef stepDef = new StepDef(parentClass, m, an); availableStepDefs.put(stepDef.getStepRegexValue(), stepDef); } else { // if the Annotation argument is not just a string it won't be a @When, @Then, @Given, @And, @But // most likeley it will be a @Before @After } } } } } } } public File outputToFile() throws IOException { String buildDir = project.getBuild().getDirectory(); File targetFolderFile = new File(buildDir); //ensure all folders are available for writing to targetFolderFile.mkdirs(); File outputFolderFile = new File(buildDir + "/stepdef.html"); FileWriter fileWriter = new FileWriter(outputFolderFile); XMLOutputter outputter = new XMLOutputter(); outputter.output(generateHtml(), fileWriter); fileWriter.close(); return outputFolderFile; } private Document generateHtml() { Document document = new Document(); Element html = new Element("html"); document.setRootElement(html); Element head = new Element("head"); Element body = new Element("body"); html.addContent(head); html.addContent(body); head.addContent(new Element("title").setText("Step definition documentation")); body.addContent(new Element("h1").setText("All steps on the classpath")); Element list = new Element("ol"); body.addContent(list); for(String key : availableStepDefs.keySet()) { StepDef stepDef = availableStepDefs.get(key); Element listItem = new Element("li"); list.addContent(listItem); listItem.addContent(new Element("h3").setText(key)); listItem.addContent(new Element("br")); listItem.addContent("found at: " + stepDef.getFullMethodName()); } return document; } public void execute() throws MojoExecutionException, MojoFailureException { try { getLog().info("SenBot documenter maven plugin will scan your calsspath for all available stepdefinitions" ); generateDocumentation(); File outputToFile = outputToFile(); getLog().info( availableStepDefs.size() + " SenBot available cucumber steps are found and documented in file: " + outputToFile.toURI().toString() ); } catch (Exception e) { throw new RuntimeException(e); } } }