/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.utils.incubator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import org.apache.commons.logging.LogFactory; import de.rcenvironment.core.utils.common.StringUtils; /** * Provisional solution for "verbose logging" flag handling. Could benefit from startup (or even runtime) configuration. * * @author Robert Mischke */ public final class DebugSettings { protected static final String VERBOSE_LOGGING_PATTERN_SYSTEM_PROPERTY = "rce.verboseLogging"; // default setting: everything disabled private static final String DEFAULT_VERBOSE_LOGGING_PATTERN = ""; // template/example for development settings; this is useful to enable logging for multiple development instances at once, instead of // adding/editing the runtime system property in several launch configurations // private static final String DEFAULT_VERBOSE_LOGGING_PATTERN = "*.NodePropertiesService,*.DistributedComponentKnowledgeService"; // singleton field private static final DebugSettings INSTANCE = new DebugSettings(); // the effective setting, configured from the constant and the optional system property private final ClassNameFilter sharedVerboseLoggingClassNameFilter; // mainly intended to suppress logging the flag state more than once per class; the caching is just an almost-free side effect - misc_ro private final Map<Class<?>, Boolean> cache = new ConcurrentHashMap<Class<?>, Boolean>(); /** * Compiles a given pattern string to a regular expression and tests given class names against it. If the pattern string is empty or * contains errors, no class name is ever matched (ie, logging is disabled). * * Note: This class is only "protected" (instead of private) for unit testing. * * @author Robert Mischke */ protected static final class ClassNameFilter { private final Pattern regexp; // null = disabled public ClassNameFilter(String patternString) { if (patternString.isEmpty()) { regexp = null; // disable return; } // TODO >6.3: check string for invalid characters String regexpString = "^(" + (patternString.replace(".", "\\.").replace("*", ".*").replace(",", "|")) + ")$"; Pattern tempRegexp = null; try { tempRegexp = Pattern.compile(regexpString); LogFactory.getLog(getClass()).info( "Using verbose logging configuration value '" + patternString + "', compiled to class name regexp '" + regexpString + "'"); } catch (PatternSyntaxException e) { System.err.println("Error in verbose logging configuration value '" + patternString + "', compiled to class name regexp '" + regexpString + "': " + e.toString()); } regexp = tempRegexp; } public boolean matches(String className) { if (regexp == null) { return false; } else { return regexp.matcher(className).matches(); } } } protected DebugSettings() { String pattern = System.getProperty(VERBOSE_LOGGING_PATTERN_SYSTEM_PROPERTY); // note that "null" (undefined) is handled differently from setting an empty string, which overrides the default with "no logging" if (pattern == null) { pattern = DEFAULT_VERBOSE_LOGGING_PATTERN; } sharedVerboseLoggingClassNameFilter = new ClassNameFilter(pattern); } /** * @param callerClass the caller's class, so verbose logging can be controlled selectively * @return true if verbose logging should be enabled for this caller */ public static boolean getVerboseLoggingEnabled(Class<?> callerClass) { return INSTANCE.getVerboseLoggingEnabledInternal(callerClass); } protected boolean getVerboseLoggingEnabledInternal(Class<?> callerClass) { Boolean cached = cache.get(callerClass); if (cached != null) { return cached; } boolean enableLogging = false; String className = callerClass.getName(); enableLogging = sharedVerboseLoggingClassNameFilter.matches(className); cache.put(callerClass, enableLogging); // thread-safe map LogFactory.getLog(DebugSettings.class).debug( StringUtils.format("Set 'verbose logging' flag to %s for %s", enableLogging, className)); return enableLogging; } }