package fitnesse.plugins;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import fitnesse.ConfigurationParameter;
import fitnesse.authentication.Authenticator;
import fitnesse.components.ComponentFactory;
import fitnesse.components.ComponentInstantiationException;
import fitnesse.reporting.Formatter;
import fitnesse.reporting.FormatterRegistry;
import fitnesse.responders.ResponderFactory;
import fitnesse.responders.editing.ContentFilter;
import fitnesse.testrunner.TestSystemFactoryRegistry;
import fitnesse.testsystems.TestSystemFactory;
import fitnesse.testsystems.slim.CustomComparator;
import fitnesse.testsystems.slim.CustomComparatorRegistry;
import fitnesse.testsystems.slim.tables.SlimTable;
import fitnesse.testsystems.slim.tables.SlimTableFactory;
import fitnesse.wiki.WikiPageFactory;
import fitnesse.wiki.WikiPageFactoryRegistry;
import fitnesse.wikitext.parser.SymbolProvider;
import fitnesse.wikitext.parser.SymbolType;
/**
* Determines which plugin features to load based on componentFactory's properties (e.g. plugins.properties).
*/
public class PropertyBasedPluginFeatureFactory extends PluginFeatureFactoryBase {
private final ComponentFactory componentFactory;
public static Collection<PluginFeatureFactory> loadFromProperties(ComponentFactory componentFactory) throws PluginException {
PropertyBasedPluginFeatureFactory propBased = new PropertyBasedPluginFeatureFactory(componentFactory);
Collection<PluginFeatureFactory> legacyWrappers = createWrappersForLegacyPlugins(componentFactory);
List<PluginFeatureFactory> all = new ArrayList<>(legacyWrappers.size() + 1);
all.add(propBased);
all.addAll(legacyWrappers);
return all;
}
private PropertyBasedPluginFeatureFactory(ComponentFactory componentFactory) {
this.componentFactory = componentFactory;
}
@Override
public void registerResponders(final ResponderFactory responderFactory) throws PluginException {
forEachNamedObject(ConfigurationParameter.RESPONDERS, new KeyRegistrar() {
@Override public void register(String key, Class clazz) {
responderFactory.addResponder(key, clazz);
LOG.info("Loaded responder " + key + ": " + clazz.getName());
}
});
}
private String[] getListFromProperties(ConfigurationParameter propertyName) {
return getListFromProperties(componentFactory, propertyName);
}
private static String[] getListFromProperties(ComponentFactory componentFactory, ConfigurationParameter propertyName) {
String value = componentFactory.getProperty(propertyName.getKey());
if (value == null)
return null;
else
return value.split(",");
}
@Override
public Authenticator getAuthenticator() {
return componentFactory.createComponent(ConfigurationParameter.AUTHENTICATOR);
}
@Override
public void registerSymbolTypes(final SymbolProvider symbolProvider) throws PluginException {
forEachObject(ConfigurationParameter.SYMBOL_TYPES, new Registrar<SymbolType>() {
@Override public void register(SymbolType instance) {
symbolProvider.add(instance);
LOG.info("Loaded SymbolType " + instance.getClass().getName());
}
});
}
@Override
public void registerWikiPageFactories(final WikiPageFactoryRegistry registrar) throws PluginException {
forEachObject(ConfigurationParameter.WIKI_PAGE_FACTORIES, new Registrar<WikiPageFactory>() {
@Override public void register(WikiPageFactory instance) {
registrar.registerWikiPageFactory(instance);
LOG.info("Loaded WikiPageFactory " + instance.getClass().getName());
}
});
}
@Override
public void registerFormatters(final FormatterRegistry registrar) throws PluginException {
forEachClass(ConfigurationParameter.FORMATTERS, new ClassRegistrar<Formatter>() {
@Override
public void register(Class<Formatter> clazz) {
registrar.registerFormatter(clazz);
LOG.info("Loaded formatter " + clazz.getName());
}
});
}
@Override
public ContentFilter getContentFilter() {
return componentFactory.createComponent(ConfigurationParameter.CONTENT_FILTER);
}
@Override
public void registerSlimTables(final SlimTableFactory slimTableFactory) throws PluginException {
forEachNamedObject(ConfigurationParameter.SLIM_TABLES, new KeyRegistrar<SlimTable>() {
@Override public void register(String key, Class<SlimTable> clazz) {
slimTableFactory.addTableType(key, clazz);
LOG.info("Loaded custom SLiM table type " + key + ":" + clazz.getName());
}
});
}
@Override
public void registerCustomComparators(final CustomComparatorRegistry customComparatorRegistry) throws PluginException {
forEachNamedObject(ConfigurationParameter.CUSTOM_COMPARATORS, new KeyRegistrar<CustomComparator>() {
@Override public void register(String key, Class<CustomComparator> clazz) {
customComparatorRegistry.addCustomComparator(key, componentFactory.createComponent(clazz));
LOG.info("Loaded custom comparator " + key + ": " + clazz.getName());
}
});
}
@Override
public void registerTestSystemFactories(final TestSystemFactoryRegistry registrar) throws PluginException {
forEachNamedObject(ConfigurationParameter.TEST_SYSTEMS, new KeyRegistrar<TestSystemFactory>() {
@Override public void register(String key, Class<TestSystemFactory> clazz) {
registrar.registerTestSystemFactory(key, componentFactory.createComponent(clazz));
LOG.info("Loaded test system " + key + ": " + clazz.getName());
}
});
}
private <T> void forEachClass(final ConfigurationParameter parameter, ClassRegistrar<T> registrar) throws PluginException {
String[] propList = getListFromProperties(parameter);
if (propList != null) {
for (String entry : propList) {
Class<T> clazz = forName(entry.trim());
registrar.register(clazz);
}
}
}
private <T> void forEachObject(final ConfigurationParameter parameter, final Registrar<T> registrar) throws PluginException {
forEachClass(parameter, new ClassRegistrar<T>() {
@Override public void register(Class<T> clazz) {
registrar.register(componentFactory.createComponent(clazz));
}
});
}
private <T> void forEachNamedObject(final ConfigurationParameter parameter, KeyRegistrar<T> registrar) throws PluginException {
String[] propList = getListFromProperties(parameter);
if (propList != null) {
for (String entry : propList) {
entry = entry.trim();
int colonIndex = entry.lastIndexOf(':');
String prefix = entry.substring(0, colonIndex);
String className = entry.substring(colonIndex + 1, entry.length());
register(registrar, prefix, className);
}
}
}
private <T> void register(KeyRegistrar<T> registrar, String prefix, String className) throws PluginException {
try {
Class<T> clazz = forName(className);
registrar.register(prefix, clazz);
} catch (ComponentInstantiationException e) {
throw new PluginException("Can not register plug in " + className, e);
}
}
private static Collection<PluginFeatureFactory> createWrappersForLegacyPlugins(ComponentFactory componentFactory) throws PluginException {
String[] pluginNames = getListFromProperties(componentFactory, ConfigurationParameter.PLUGINS);
if (pluginNames == null) {
return Collections.emptyList();
} else {
List<PluginFeatureFactory> providers = new ArrayList<>(pluginNames.length);
for (String pluginName : pluginNames) {
Class<?> pluginClass = forName(pluginName);
Object plugin = componentFactory.createComponent(pluginClass);
providers.add(new LegacyPluginFeatureFactory(plugin));
}
return providers;
}
}
@SuppressWarnings("unchecked")
private static <T> Class<T> forName(String className) throws PluginException {
try {
return (Class<T>) Class.forName(className);
} catch (ClassNotFoundException e) {
throw new PluginException("Unable to load class " + className, e);
}
}
private interface Registrar<T> {
void register(T instance);
}
private interface ClassRegistrar<T> {
void register(Class<T> clazz);
}
private interface KeyRegistrar<T> {
void register(String key, Class<T> clazz);
}
}