package org.geoserver.platform; import java.io.File; import java.util.Arrays; import java.util.Map; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; /** * Helper class for using GeoServerExtensions in a test environment. * <p> * This class allows the insertion of beans, properties and files into the * GeoServerExtensions cache to facilitate testing. * </p> * <h2>Singleton Beans</h2> * <p> * As a concession to mocking test cases, a few singletons can be registered by hand: * <pre><code> * @Before * public void before(){ * GeoServerResourceLoader loader = new GeoServerResourceLoader(baseDirectory); * GeoServerExtensionsHelper.singleton( "resourceLoader", loader ); * } * @After * public void after(){ * GeoServerExtensionsHelper.clear(); * } * </code><pre> * Warnings provided by {@link #checkContext(ApplicationContext, String)} are suppressed when using {@link #init(Object)}. * * @author Jody Garnett (Boundless) */ public class GeoServerExtensionsHelper { /** * Flag to identify use of spring context via {@link #setApplicationContext(ApplicationContext)} and * enable additional consistency checks for missing extensions. */ public static void setIsSpringContext(boolean isSpring){ GeoServerExtensions.isSpringContext = isSpring; } /** * Clear caches used by GeoServerExtensions. */ public static void clear(){ GeoServerExtensions.extensionsCache.clear(); GeoServerExtensions.singletonBeanCache.clear(); GeoServerExtensions.propertyCache.clear(); GeoServerExtensions.fileCache.clear(); } /** * Sets the web application context to be used for looking up extensions. * <p> * This is the context that is used for methods which don't supply their * own context. * </p> * @param context ApplicationContext used to lookup extensions */ public static void init(ApplicationContext context) throws BeansException { GeoServerExtensions.isSpringContext = false; GeoServerExtensions.context = context; clear(); } /** * Directly register singleton for use with {@link GeoServerExtensions#bean(String)} (and {@link GeoServerExtensions#bean(Class)}). * <p> * If GeoServerExtensions has been configured with a context * @param name Singleton name * @param bean Singleton */ public static void singleton(String name, Object bean, Class<?>... declaredClasses) { if( GeoServerExtensions.context != null ){ if( GeoServerExtensions.context.containsBean(name) ){ Object conflict = GeoServerExtensions.context.getBean(name); if( bean != conflict ){ GeoServerExtensions.LOGGER.fine("ApplicationContext override "+name+": "+conflict); } } } else { GeoServerExtensions.isSpringContext = false; } if( name == null || bean == null ){ return; } GeoServerExtensions.singletonBeanCache.put( name, bean ); if (declaredClasses != null && declaredClasses.length > 0) { for (Class<?> clazz : declaredClasses) { addToCache(GeoServerExtensions.extensionsCache, clazz, name); } } else { Class<?> type = bean.getClass(); addToCache(GeoServerExtensions.extensionsCache, type, name); } } static <T> void addToCache(Map<T, String[]> cache, T key, String name) { String[] cached = cache.get(key); if(cached!=null) { cached = Arrays.copyOf(cached, cached.length+1); cached[cached.length-1] = name; } else { cached = new String[]{name}; } cache.put(key, cached); } /** * Directly register property for use with {@link GeoServerExtensions#getProperty(String)}. */ public static void property(String propertyName, String property ){ GeoServerExtensions.propertyCache.put(propertyName, property ); } /** * Directly register file for use with {@link GeoServerExtensions#file(String)}. */ public static void file(String path, File file ){ GeoServerExtensions.fileCache.put(path, file); } /** * JUnit Rule which automatically initialises and clears mocked extensions. * * @author Kevin Smith, Boundless * */ public static class ExtensionsHelperRule implements TestRule { ApplicationContext context; Boolean isSpringContext; Boolean active =false; public Statement apply(Statement base, Description description) { return statement(base); } private Statement statement(final Statement base) { return new Statement() { @Override public void evaluate() throws Throwable { try { if(context!=null){ GeoServerExtensionsHelper.init(context); } else { GeoServerExtensionsHelper.clear(); } if(isSpringContext!=null){ GeoServerExtensionsHelper.setIsSpringContext(isSpringContext); } active=true; base.evaluate(); } finally { active=false; GeoServerExtensionsHelper.clear(); } } }; } /** * Directly register singleton for use with {@link GeoServerExtensions#bean(String)} (and {@link GeoServerExtensions#bean(Class)}). * <p> * If GeoServerExtensions has been configured with a context * @param name Singleton name * @param bean Singleton */ public void singleton(String name, Object bean, Class<?>... declaredClasses){ if(!active) throw new IllegalStateException(); GeoServerExtensionsHelper.singleton(name, bean, declaredClasses); } /** * Directly register property for use with {@link GeoServerExtensions#getProperty(String)}. */ public void property(String propertyName, String property ){ if(!active) throw new IllegalStateException(); GeoServerExtensionsHelper.property(propertyName, property ); } /** * Directly register file for use with {@link GeoServerExtensions#file(String)}. */ public void file(String path, File file ){ if(!active) throw new IllegalStateException(); GeoServerExtensionsHelper.file(path, file); } } }