All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cucumber.runtime.formatter.PluginFactory Maven / Gradle / Ivy

There is a newer version: 7.18.0
Show newest version
package cucumber.runtime.formatter;

import cucumber.api.Plugin;
import cucumber.api.StepDefinitionReporter;
import cucumber.api.SummaryPrinter;
import cucumber.api.formatter.Formatter;
import cucumber.runtime.CucumberException;
import cucumber.runtime.DefaultSummaryPrinter;
import cucumber.runtime.NullSummaryPrinter;
import cucumber.runtime.io.URLOutputStream;
import cucumber.runtime.io.UTF8OutputStreamWriter;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static cucumber.runtime.Utils.toURL;
import static java.util.Arrays.asList;

/**
 * This class creates plugin instances from a String.
 * 

* The String is of the form name[:output] where name is either a fully qualified class name or one of the built-in * short names. The output is optional for some plugins (and mandatory for some). * * * @see Plugin for specific requirements */ public final class PluginFactory { private final Class[] CTOR_PARAMETERS = new Class[]{String.class, Appendable.class, URI.class, URL.class, File.class}; private static final HashMap> PLUGIN_CLASSES = new HashMap>() {{ put("null", NullFormatter.class); put("junit", JUnitFormatter.class); put("testng", TestNGFormatter.class); put("html", HTMLFormatter.class); put("pretty", PrettyFormatter.class); put("progress", ProgressFormatter.class); put("json", JSONFormatter.class); put("usage", UsageFormatter.class); put("rerun", RerunFormatter.class); put("default_summary", DefaultSummaryPrinter.class); put("null_summary", NullSummaryPrinter.class); }}; private static final Pattern PLUGIN_WITH_ARGUMENT_PATTERN = Pattern.compile("([^:]+):(.*)"); private String defaultOutFormatter = null; private Appendable defaultOut = new PrintStream(System.out) { @Override public void close() { // We have no intention to close System.out } }; public Plugin create(String pluginString) { Matcher pluginWithArgument = PLUGIN_WITH_ARGUMENT_PATTERN.matcher(pluginString); String pluginName; String argument; if (pluginWithArgument.matches()) { pluginName = pluginWithArgument.group(1); argument = pluginWithArgument.group(2); } else { pluginName = pluginString; argument = null; } Class pluginClass = pluginClass(pluginName); try { return instantiate(pluginString, pluginClass, argument); } catch (IOException e) { throw new CucumberException(e); } catch (URISyntaxException e) { throw new CucumberException(e); } } private T instantiate(String pluginString, Class pluginClass, String argument) throws IOException, URISyntaxException { Constructor single = findSingleArgConstructor(pluginClass); Constructor empty = findEmptyConstructor(pluginClass); if (single != null) { Object ctorArg = convertOrNull(argument, single.getParameterTypes()[0], pluginString); if (ctorArg != null) return newInstance(single, ctorArg); } if (argument == null && empty != null) { return newInstance(empty); } if (single != null) throw new CucumberException(String.format("You must supply an output argument to %s. Like so: %s:output", pluginString, pluginString)); throw new CucumberException(String.format("%s must have a constructor that is either empty or a single arg of one of: %s", pluginClass, asList(CTOR_PARAMETERS))); } private T newInstance(Constructor constructor, Object... ctorArgs) { try { return constructor.newInstance(ctorArgs); } catch (InstantiationException e) { throw new CucumberException(e); } catch (IllegalAccessException e) { throw new CucumberException(e); } catch (InvocationTargetException e) { throw new CucumberException(e.getTargetException()); } } private Object convertOrNull(String arg, Class ctorArgClass, String formatterString) throws IOException, URISyntaxException { if (arg == null) { if (ctorArgClass.equals(Appendable.class)) { return defaultOutOrFailIfAlreadyUsed(formatterString); } else { return null; } } if (ctorArgClass.equals(URI.class)) { return new URI(arg); } if (ctorArgClass.equals(URL.class)) { return toURL(arg); } if (ctorArgClass.equals(File.class)) { return new File(arg); } if (ctorArgClass.equals(String.class)) { return arg; } if (ctorArgClass.equals(Appendable.class)) { return new UTF8OutputStreamWriter(new URLOutputStream(toURL(arg))); } return null; } private Constructor findSingleArgConstructor(Class pluginClass) { Constructor constructor = null; for (Class ctorArgClass : CTOR_PARAMETERS) { try { Constructor candidate = pluginClass.getConstructor(ctorArgClass); if (constructor != null) { throw new CucumberException(String.format("Plugin %s should only define a single one-argument constructor", pluginClass.getName())); } constructor = candidate; } catch (NoSuchMethodException ignore) { } } return constructor; } private Constructor findEmptyConstructor(Class pluginClass) { try { return pluginClass.getConstructor(); } catch (NoSuchMethodException ignore) { return null; } } private static Class pluginClass(String pluginName) { Class pluginClass = PLUGIN_CLASSES.get(pluginName); if (pluginClass == null) { pluginClass = loadClass(pluginName); } return pluginClass; } @SuppressWarnings("unchecked") private static Class loadClass(String className) { try { Class aClass = Thread.currentThread().getContextClassLoader().loadClass(className); if (Plugin.class.isAssignableFrom(aClass)) { return (Class) aClass; } throw new CucumberException("Couldn't load plugin class: " + className + ". It does not implement " + Plugin.class.getName()); } catch (ClassNotFoundException e) { throw new CucumberException("Couldn't load plugin class: " + className, e); } } private Appendable defaultOutOrFailIfAlreadyUsed(String formatterString) { try { if (defaultOut != null) { defaultOutFormatter = formatterString; return defaultOut; } else { throw new CucumberException("Only one formatter can use STDOUT, now both " + defaultOutFormatter + " and " + formatterString + " use it. " + "If you use more than one formatter you must specify output path with PLUGIN:PATH_OR_URL"); } } finally { defaultOut = null; } } public static boolean isFormatterName(String name) { Class pluginClass = getPluginClass(name); return Formatter.class.isAssignableFrom(pluginClass); } public static boolean isStepDefinitionReporterName(String name) { Class pluginClass = getPluginClass(name); return StepDefinitionReporter.class.isAssignableFrom(pluginClass); } public static boolean isSummaryPrinterName(String name) { Class pluginClass = getPluginClass(name); return SummaryPrinter.class.isAssignableFrom(pluginClass); } private static Class getPluginClass(String name) { Matcher pluginWithFile = PLUGIN_WITH_ARGUMENT_PATTERN.matcher(name); String pluginName; if (pluginWithFile.matches()) { pluginName = pluginWithFile.group(1); } else { pluginName = name; } return pluginClass(pluginName); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy