package de.is24.util.monitoring;
import de.is24.util.monitoring.keyhandler.DefaultKeyEscaper;
import de.is24.util.monitoring.keyhandler.KeyHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* This is a helper class for testing appmon4j integration.
* For example it allows a clean initialization of the InApplicationMonitor instance in a setup @before method.
*
* This class partially exposes methods, usually not available, and thus should not be used in production code.
* Especially as this code may induce concurrence problems in a multi threading environment.
*
* @see de.is24.util.monitoring.TestHelper
* @see de.is24.util.monitoring.InApplicationMonitorRule
*/
public class TestingInApplicationMonitor extends InApplicationMonitor {
private static final Logger LOGGER = LoggerFactory.getLogger(TestingInApplicationMonitor.class);
private static final ThreadLocal<CorePlugin> threadLocalCorePlugin = new InheritableThreadLocal<CorePlugin>();
private static final ThreadLocal<List<MonitorPlugin>> threadLocalPluginsList =
new InheritableThreadLocal<List<MonitorPlugin>>();
public TestingInApplicationMonitor(CorePlugin corePlugin, KeyHandler keyHandler) {
super(corePlugin, keyHandler);
}
/**
* This will fail if tests are run multi threaded use with utmost care.
*/
public static InApplicationMonitor initInstanceForTesting(CorePlugin corePlugin, KeyHandler keyHandler) {
synchronized (semaphore) {
if (instance != null) {
instance.getCorePlugin().destroy();
}
LOGGER.info("+++ Changing InApplicationMonitor() for Testing only +++");
instance = new TestingInApplicationMonitor(corePlugin, keyHandler);
LOGGER.info("InApplicationMonitor changed successfully.");
return instance;
}
}
/**
* This will fail if tests are run multi threaded use with utmost care.
*/
public static void resetInstanceForTesting() {
synchronized (semaphore) {
if (instance != null) {
instance.getCorePlugin().destroy();
}
KeyHandler keyHandler = new DefaultKeyEscaper();
CorePlugin corePlugin = new CorePlugin(null, keyHandler);
instance = new TestingInApplicationMonitor(corePlugin, keyHandler);
LOGGER.info("Reset InApplicationMonitor for Testing.");
}
}
@Override
public CorePlugin getCorePlugin() {
CorePlugin result = threadLocalCorePlugin.get();
if (result == null) {
result = super.getCorePlugin();
}
return result;
}
@Override
public List<MonitorPlugin> getPlugins() {
List<MonitorPlugin> result = threadLocalPluginsList.get();
if (result == null) {
result = super.getPlugins();
}
return result;
}
/**
* this method allows Tests running multi threaded to achieve some level of isolation against
* activities from other threads. All methods handed over to the CorePlugin will be handled
* by a dedicated CorePlugin instance for the calling thread, and all threads created
* by this thread.
*
* So this is currently only helpfull for StateValueProviders, MultiValueProviders and Versions.
*
* This core plugin will even "survive" calls to @seet resetInstanceForTesting or @see initInstanceForTesting
* calls in other threads.
*
* The dedicated CorePlugin will not be accessible via JMX, only the original CorePlugins data will be available
* via JMX.
*/
@Override
public void setThreadLocalState() {
CorePlugin corePlugin = new CorePlugin(null, getKeyHandler());
threadLocalCorePlugin.set(corePlugin);
CopyOnWriteArrayList<MonitorPlugin> monitorPlugins = new CopyOnWriteArrayList<MonitorPlugin>();
monitorPlugins.add(corePlugin);
threadLocalPluginsList.set(monitorPlugins);
}
@Override
public void resetThreadLocalState() {
threadLocalCorePlugin.remove();
threadLocalPluginsList.remove();
}
}