Last active
October 2, 2018 16:17
-
-
Save jamezp/68cd45982ba2b75aa2e95465695ec061 to your computer and use it in GitHub Desktop.
Example Log Configuration Change Updater
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* JBoss, Home of Professional Open Source. | |
* | |
* Copyright 2018 Red Hat, Inc., and individual contributors | |
* as indicated by the @author tags. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package org.jboss.logmanager; | |
import java.nio.file.Path; | |
import java.nio.file.Paths; | |
import java.util.concurrent.ExecutorService; | |
import java.util.concurrent.Executors; | |
import java.util.concurrent.TimeUnit; | |
import org.jboss.logging.Logger; | |
/** | |
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a> | |
*/ | |
public class Example { | |
public static void main(String[] args) throws Exception { | |
final Path loggingConfig = Paths.get(System.getProperty("user.home"), "/tmp/logging.properties"); | |
System.setProperty("java.util.logging.manager", "org.jboss.logmanager.LogManager"); | |
System.setProperty("logging.configuration", "file://" + loggingConfig.toString()); | |
System.setProperty("log.dir", "/home/jperkins/tmp/logs"); | |
final Logger logger = Logger.getLogger(Example.class); | |
final ExecutorService service = Executors.newCachedThreadPool(); | |
final LoggingConfigurationChangeListener listener = new LoggingConfigurationChangeListener(loggingConfig); | |
try { | |
service.submit(listener); | |
service.submit(new Runnable() { | |
@Override | |
public void run() { | |
for (; ; ) { | |
logger.trace("Test trace"); | |
logger.debug("Test debug"); | |
logger.info("Test info"); | |
logger.warn("Test warn"); | |
logger.error("Test error"); | |
try { | |
TimeUnit.SECONDS.sleep(3L); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
}); | |
} finally { | |
service.shutdown(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* JBoss, Home of Professional Open Source. | |
* | |
* Copyright 2018 Red Hat, Inc., and individual contributors | |
* as indicated by the @author tags. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package org.jboss.logmanager; | |
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; | |
import static java.nio.file.StandardWatchEventKinds.OVERFLOW; | |
import java.io.Closeable; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.nio.file.ClosedWatchServiceException; | |
import java.nio.file.FileSystems; | |
import java.nio.file.Files; | |
import java.nio.file.Path; | |
import java.nio.file.StandardWatchEventKinds; | |
import java.nio.file.WatchEvent; | |
import java.nio.file.WatchKey; | |
import java.nio.file.WatchService; | |
import java.util.concurrent.locks.Lock; | |
import java.util.concurrent.locks.ReentrantLock; | |
import org.jboss.logmanager.config.LogContextConfiguration; | |
/** | |
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a> | |
*/ | |
public class LoggingConfigurationChangeListener implements Runnable, Closeable { | |
private static final Logger.AttachmentKey<LoggingConfigurationUpdater> KEY = new Logger.AttachmentKey<>(); | |
private static final Logger LOGGER = Logger.getLogger(LoggingConfigurationChangeListener.class.getName()); | |
private final WatchService watcher; | |
private final Path configFile; | |
private final Lock lock; | |
@SuppressWarnings("WeakerAccess") | |
public LoggingConfigurationChangeListener(final Path configFile) throws IOException { | |
this.configFile = configFile; | |
lock = new ReentrantLock(); | |
watcher = FileSystems.getDefault().newWatchService(); | |
configFile.getParent().register(watcher, StandardWatchEventKinds.ENTRY_MODIFY); | |
} | |
@Override | |
public void run() { | |
try { | |
for (; ; ) { | |
// Wait for signal | |
final WatchKey key; | |
try { | |
key = watcher.take(); | |
} catch (InterruptedException x) { | |
x.printStackTrace(); | |
return; | |
} | |
for (WatchEvent<?> event : key.pollEvents()) { | |
if (event.kind() == OVERFLOW) { | |
continue; | |
} | |
// Context for directory entry event is the file name of entry | |
@SuppressWarnings("unchecked") | |
final WatchEvent<Path> ev = (WatchEvent<Path>) event; | |
final Path file = ev.context(); | |
if (event.kind() == ENTRY_MODIFY && file.getFileName().equals(configFile.getFileName())) { | |
final LoggingConfigurationUpdater updater = getOrCreateUpdater(); | |
if (updater == null) { | |
System.err.printf("Could not listen for configuration changes on %s. The LogContextConfiguration could not be found.%n", configFile); | |
break; | |
} | |
try (InputStream in = Files.newInputStream(configFile)) { | |
lock.lock(); | |
updater.configure(in); | |
} catch (Exception e) { | |
System.err.println("Failed to process changes to the logging configuration file."); | |
e.printStackTrace(System.err); | |
} finally { | |
lock.unlock(); | |
} | |
} | |
} | |
// Reset the key and remove from the registry if it's no longer available | |
boolean valid = key.reset(); | |
if (!valid) { | |
break; | |
} | |
} | |
} catch (ClosedWatchServiceException e) { | |
LOGGER.log(Level.DEBUG, "Configuration change listener has been closed."); | |
} | |
} | |
@Override | |
public void close() throws IOException { | |
watcher.close(); | |
} | |
private LoggingConfigurationUpdater getOrCreateUpdater() { | |
final LogContext logContext = LogContext.getLogContext(); | |
final Logger rootLogger = logContext.getLogger(""); | |
LoggingConfigurationUpdater updater = rootLogger.getAttachment(KEY); | |
if (updater == null) { | |
final LogContextConfiguration logContextConfiguration = getOrCreateConfiguration(rootLogger); | |
if (logContextConfiguration == null) { | |
return null; | |
} | |
updater = new LoggingConfigurationUpdater(logContextConfiguration); | |
final LoggingConfigurationUpdater appearing = rootLogger.attachIfAbsent(KEY, updater); | |
if (appearing != null) { | |
updater = appearing; | |
} | |
} | |
return updater; | |
} | |
private LogContextConfiguration getOrCreateConfiguration(final Logger rootLogger) { | |
Configurator configurator = rootLogger.getAttachment(Configurator.ATTACHMENT_KEY); | |
if (configurator == null) { | |
configurator = new PropertyConfigurator(rootLogger.getLogContext()); | |
final Configurator appearing = rootLogger.attachIfAbsent(Configurator.ATTACHMENT_KEY, configurator); | |
if (appearing != null) { | |
configurator = appearing; | |
} | |
} | |
if (configurator instanceof PropertyConfigurator) { | |
return ((PropertyConfigurator) configurator).getLogContextConfiguration(); | |
} | |
return null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* JBoss, Home of Professional Open Source. | |
* | |
* Copyright 2018 Red Hat, Inc., and individual contributors | |
* as indicated by the @author tags. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package org.jboss.logmanager; | |
import java.io.Closeable; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.InputStreamReader; | |
import java.nio.charset.StandardCharsets; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.Collection; | |
import java.util.List; | |
import java.util.Objects; | |
import java.util.Properties; | |
import java.util.regex.Pattern; | |
import org.jboss.logmanager.config.ErrorManagerConfiguration; | |
import org.jboss.logmanager.config.FilterConfiguration; | |
import org.jboss.logmanager.config.FormatterConfiguration; | |
import org.jboss.logmanager.config.HandlerConfiguration; | |
import org.jboss.logmanager.config.HandlerContainingConfigurable; | |
import org.jboss.logmanager.config.LogContextConfiguration; | |
import org.jboss.logmanager.config.LoggerConfiguration; | |
import org.jboss.logmanager.config.PojoConfiguration; | |
import org.jboss.logmanager.config.PropertyConfigurable; | |
import org.jboss.logmanager.config.ValueExpression; | |
/** | |
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a> | |
*/ | |
@SuppressWarnings("WeakerAccess") | |
public class LoggingConfigurationUpdater { | |
private static final String[] EMPTY_STRINGS = new String[0]; | |
private static final Pattern EXPRESSION_PATTERN = Pattern.compile(".*\\$\\{.*\\}.*"); | |
private final LogContextConfiguration config; | |
public LoggingConfigurationUpdater(final LogContextConfiguration config) { | |
this.config = config; | |
} | |
/** | |
* {@inheritDoc} | |
*/ | |
public void configure(final InputStream inputStream) throws IOException { | |
final Properties properties = new Properties(); | |
try { | |
properties.load(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); | |
inputStream.close(); | |
} finally { | |
safeClose(inputStream); | |
} | |
configure(properties); | |
} | |
/** | |
* Configure the log manager from the given properties. | |
* <p/> | |
* The following values read in from a configuration will be trimmed of prefixed and trailing whitespace: | |
* <pre> | |
* <ul> | |
* <li>logger.NAME.filter</li> | |
* <li>logger.NAME.level</li> | |
* <li>logger.NAME.useParentHandlers</li> | |
* <li>handler.NAME.filter</li> | |
* <li>handler.NAME.formatter</li> | |
* <li>handler.NAME.level</li> | |
* <li>handler.NAME.encoding</li> | |
* <li>handler.NAME.errorManager</li> | |
* </ul> | |
* </pre> | |
* | |
* @param properties the properties | |
*/ | |
private void configure(final Properties properties) { | |
try { | |
final Collection<String> handlersToRemove = config.getHandlerNames(); | |
// Start with the list of loggers to configure. The root logger is always on the list. | |
handlersToRemove.removeAll(configureLogger(properties, "")); | |
// And, for each logger name, configure any filters, handlers, etc. | |
final String[] loggerNames = getStringCsvArray(properties, "loggers"); | |
for (String loggerName : loggerNames) { | |
handlersToRemove.removeAll(configureLogger(properties, loggerName)); | |
} | |
// Remove any loggers that are not longer required | |
final Collection<String> loggersToRemove = config.getLoggerNames(); | |
loggersToRemove.remove(""); | |
loggersToRemove.removeAll(Arrays.asList(loggerNames)); | |
for (String loggerName : loggersToRemove) { | |
config.removeLoggerConfiguration(loggerName); | |
} | |
// Configure any declared handlers. | |
final String[] handlerNames = getStringCsvArray(properties, "handlers"); | |
for (String handlerName : handlerNames) { | |
configureHandler(properties, handlerName); | |
} | |
// Remove any handlers that are not longer required | |
handlersToRemove.removeAll(Arrays.asList(handlerNames)); | |
for (String handlerName : handlersToRemove) { | |
config.removeHandlerConfiguration(handlerName); | |
} | |
// Configure any declared filters. | |
for (String filterName : getStringCsvArray(properties, "filters")) { | |
configureFilter(properties, filterName); | |
} | |
// Configure any declared formatters. | |
for (String formatterName : getStringCsvArray(properties, "formatters")) { | |
configureFormatter(properties, formatterName); | |
} | |
// Configure any declared error managers. | |
for (String errorManagerName : getStringCsvArray(properties, "errorManagers")) { | |
configureErrorManager(properties, errorManagerName); | |
} | |
// Configure POJOs | |
for (String pojoName : getStringCsvArray(properties, "pojos")) { | |
configurePojos(properties, pojoName); | |
} | |
config.commit(); | |
} finally { | |
config.forget(); | |
} | |
} | |
private List<String> configureLogger(final Properties properties, final String loggerName) { | |
final LoggerConfiguration loggerConfiguration; | |
if (config.getLoggerNames().contains(loggerName)) { | |
loggerConfiguration = config.getLoggerConfiguration(loggerName); | |
} else { | |
loggerConfiguration = config.addLoggerConfiguration(loggerName); | |
} | |
// Get logger level | |
final String levelName = getStringProperty(properties, getKey("logger", loggerName, "level")); | |
if (notEqual(levelName, loggerConfiguration.getLevelValueExpression())) { | |
loggerConfiguration.setLevel(levelName == null ? "ALL" : levelName); | |
} | |
// Get logger filter | |
final String filterName = getStringProperty(properties, getKey("logger", loggerName, "filter")); | |
final ValueExpression<String> newValue = ValueExpression.STRING_RESOLVER.resolve(filterName); | |
if (notEqual(newValue, loggerConfiguration.getFilterValueExpression())) { | |
loggerConfiguration.setFilter(filterName); | |
final String resolvedFilter = loggerConfiguration.getFilterValueExpression().getResolvedValue(); | |
if (resolvedFilter != null) { | |
// Check for a filter class | |
final String filterClassName = getStringProperty(properties, getKey("filter", resolvedFilter)); | |
// If the filter class is null, assume it's a filter expression | |
if (filterClassName != null) { | |
configureFilter(properties, resolvedFilter); | |
} | |
} | |
} | |
// Get logger handlers | |
configureHandlerNames(properties, loggerConfiguration, "logger", loggerName); | |
// Get logger properties | |
final String useParentHandlersString = getStringProperty(properties, getKey("logger", loggerName, "useParentHandlers")); | |
if (booleanNotEqual(useParentHandlersString, loggerConfiguration.getUseParentHandlersValueExpression())) { | |
// Check for expression | |
if (EXPRESSION_PATTERN.matcher(useParentHandlersString).matches()) { | |
loggerConfiguration.setUseParentHandlers(useParentHandlersString); | |
} else { | |
loggerConfiguration.setUseParentHandlers(Boolean.parseBoolean(useParentHandlersString)); | |
} | |
} | |
return loggerConfiguration.getHandlerNames(); | |
} | |
private void configureFilter(final Properties properties, final String filterName) { | |
final String className = getStringProperty(properties, getKey("filter", filterName)); | |
if (className == null) { | |
// Assume we're using a filter expression | |
return; | |
} | |
final FilterConfiguration configuration; | |
if (config.getFilterNames().contains(filterName)) { | |
configuration = config.getFilterConfiguration(filterName); | |
} else { | |
configuration = config.addFilterConfiguration( | |
getStringProperty(properties, getKey("filter", filterName, "module")), | |
className, | |
filterName, | |
getStringCsvArray(properties, getKey("filter", filterName, "constructorProperties"))); | |
} | |
final String[] postConfigurationMethods = getStringCsvArray(properties, getKey("filter", filterName, "postConfiguration")); | |
configuration.setPostConfigurationMethods(postConfigurationMethods); | |
configureProperties(properties, configuration, getKey("filter", filterName)); | |
} | |
private boolean configureFormatter(final Properties properties, final String formatterName) { | |
final String className = getStringProperty(properties, getKey("formatter", formatterName)); | |
if (className == null) { | |
printError("Formatter %s is not defined%n", formatterName); | |
return false; | |
} | |
final FormatterConfiguration configuration; | |
if (config.getFormatterNames().contains(formatterName)) { | |
configuration = config.getFormatterConfiguration(formatterName); | |
} else { | |
configuration = config.addFormatterConfiguration( | |
getStringProperty(properties, getKey("formatter", formatterName, "module")), | |
className, | |
formatterName, | |
getStringCsvArray(properties, getKey("formatter", formatterName, "constructorProperties"))); | |
} | |
final String[] postConfigurationMethods = getStringCsvArray(properties, getKey("formatter", formatterName, "postConfiguration")); | |
configuration.setPostConfigurationMethods(postConfigurationMethods); | |
configureProperties(properties, configuration, getKey("formatter", formatterName)); | |
return true; | |
} | |
private boolean configureErrorManager(final Properties properties, final String errorManagerName) { | |
final String className = getStringProperty(properties, getKey("errorManager", errorManagerName)); | |
if (className == null) { | |
printError("Error manager %s is not defined%n", errorManagerName); | |
return false; | |
} | |
final ErrorManagerConfiguration configuration; | |
if (config.getErrorManagerNames().contains(errorManagerName)) { | |
configuration = config.getErrorManagerConfiguration(errorManagerName); | |
} else { | |
configuration = config.addErrorManagerConfiguration( | |
getStringProperty(properties, getKey("errorManager", errorManagerName, "module")), | |
className, | |
errorManagerName, | |
getStringCsvArray(properties, getKey("errorManager", errorManagerName, "constructorProperties"))); | |
} | |
final String[] postConfigurationMethods = getStringCsvArray(properties, getKey("errorManager", errorManagerName, "postConfiguration")); | |
configuration.setPostConfigurationMethods(postConfigurationMethods); | |
configureProperties(properties, configuration, getKey("errorManager", errorManagerName)); | |
return true; | |
} | |
private boolean configureHandler(final Properties properties, final String handlerName) { | |
final String className = getStringProperty(properties, getKey("handler", handlerName)); | |
if (className == null) { | |
printError("Handler %s is not defined%n", handlerName); | |
return false; | |
} | |
final HandlerConfiguration configuration; | |
if (config.getHandlerNames().contains(handlerName)) { | |
configuration = config.getHandlerConfiguration(handlerName); | |
} else { | |
configuration = config.addHandlerConfiguration( | |
getStringProperty(properties, getKey("handler", handlerName, "module")), | |
className, | |
handlerName, | |
getStringCsvArray(properties, getKey("handler", handlerName, "constructorProperties"))); | |
} | |
final String filter = getStringProperty(properties, getKey("handler", handlerName, "filter")); | |
if (notEqual(filter, configuration.getFilterValueExpression())) { | |
configuration.setFilter(filter); | |
final String resolvedFilter = configuration.getFilterValueExpression().getResolvedValue(); | |
if (resolvedFilter != null) { | |
// Check for a filter class | |
final String filterClassName = getStringProperty(properties, getKey("filter", resolvedFilter)); | |
// If the filter class is null, assume it's a filter expression | |
if (filterClassName != null) { | |
configureFilter(properties, resolvedFilter); | |
} | |
} | |
} | |
final String levelName = getStringProperty(properties, getKey("handler", handlerName, "level")); | |
if (notEqual(levelName, configuration.getLevelValueExpression())) { | |
configuration.setLevel(levelName == null ? "ALL" : levelName); | |
} | |
final String formatterName = getStringProperty(properties, getKey("handler", handlerName, "formatter")); | |
if (formatterName != null) { | |
if (getStringProperty(properties, getKey("formatter", ValueExpression.STRING_RESOLVER.resolve(formatterName).getResolvedValue())) == null) { | |
printError("Formatter %s is not defined%n", formatterName); | |
} else { | |
final ValueExpression<String> newValue = ValueExpression.STRING_RESOLVER.resolve(formatterName); | |
final boolean changed = configureFormatter(properties, newValue.getResolvedValue()); | |
if (notEqual(newValue, configuration.getFormatterNameValueExpression())) { | |
if (changed) { | |
configuration.setFormatterName(formatterName); | |
} | |
} | |
} | |
} | |
final String encoding = getStringProperty(properties, getKey("handler", handlerName, "encoding")); | |
if (notEqual(encoding, configuration.getEncodingValueExpression())) { | |
configuration.setEncoding(encoding); | |
} | |
final String errorManagerName = getStringProperty(properties, getKey("handler", handlerName, "errorManager")); | |
if (errorManagerName != null) { | |
if (getStringProperty(properties, getKey("errorManager", ValueExpression.STRING_RESOLVER.resolve(errorManagerName).getResolvedValue())) == null) { | |
printError("Error manager %s is not defined%n", errorManagerName); | |
} else { | |
final ValueExpression<String> newValue = ValueExpression.STRING_RESOLVER.resolve(errorManagerName); | |
final boolean changed = configureFormatter(properties, newValue.getResolvedValue()); | |
if (notEqual(newValue, configuration.getErrorManagerNameValueExpression())) { | |
if (changed) { | |
configuration.setErrorManagerName(errorManagerName); | |
} | |
} | |
} | |
} | |
configureHandlerNames(properties, configuration, "handler", handlerName); | |
final String[] postConfigurationMethods = getStringCsvArray(properties, getKey("handler", handlerName, "postConfiguration")); | |
configuration.setPostConfigurationMethods(postConfigurationMethods); | |
configureProperties(properties, configuration, getKey("handler", handlerName)); | |
return true; | |
} | |
private void configurePojos(final Properties properties, final String pojoName) { | |
final String className = getStringProperty(properties, getKey("pojo", pojoName)); | |
if (className == null) { | |
printError("POJO %s is not defined%n", pojoName); | |
return; | |
} | |
final PojoConfiguration configuration; | |
if (config.getPojoNames().contains(pojoName)) { | |
configuration = config.getPojoConfiguration(pojoName); | |
} else { | |
configuration = config.addPojoConfiguration( | |
getStringProperty(properties, getKey("pojo", pojoName, "module")), | |
getStringProperty(properties, getKey("pojo", pojoName)), | |
pojoName, | |
getStringCsvArray(properties, getKey("pojo", pojoName, "constructorProperties"))); | |
} | |
final String[] postConfigurationMethods = getStringCsvArray(properties, getKey("pojo", pojoName, "postConfiguration")); | |
configuration.setPostConfigurationMethods(postConfigurationMethods); | |
configureProperties(properties, configuration, getKey("pojo", pojoName)); | |
} | |
private void configureProperties(final Properties properties, final PropertyConfigurable configurable, final String prefix) { | |
final List<String> propertyNames = getStringCsvList(properties, getKey(prefix, "properties")); | |
for (String propertyName : propertyNames) { | |
final String valueString = getStringProperty(properties, getKey(prefix, propertyName), false); | |
if (notEqual(valueString, configurable.getPropertyValueExpression(propertyName))) { | |
configurable.setPropertyValueString(propertyName, valueString); | |
} | |
} | |
} | |
private void configureHandlerNames(final Properties properties, final HandlerContainingConfigurable configuration, | |
final String prefix, final String name) { | |
final String[] handlerNames = getStringCsvArray(properties, getKey(prefix, name, "handlers")); | |
final Collection<String> availableHandlers = new ArrayList<>(); | |
for (String handlerName : handlerNames) { | |
if (configureHandler(properties, handlerName)) { | |
availableHandlers.add(handlerName); | |
} | |
} | |
configuration.setHandlerNames(availableHandlers); | |
} | |
private static String getKey(final String prefix, final String objectName) { | |
return objectName.length() > 0 ? prefix + "." + objectName : prefix; | |
} | |
private static String getKey(final String prefix, final String objectName, final String key) { | |
return objectName.length() > 0 ? prefix + "." + objectName + "." + key : prefix + "." + key; | |
} | |
private static String getStringProperty(final Properties properties, final String key) { | |
return getStringProperty(properties, key, true); | |
} | |
private static String getStringProperty(final Properties properties, final String key, final boolean trim) { | |
final String value = properties.getProperty(key); | |
return (trim ? (value == null ? null : value.trim()) : value); | |
} | |
private static String[] getStringCsvArray(final Properties properties, final String key) { | |
final String property = properties.getProperty(key, ""); | |
if (property == null) { | |
return EMPTY_STRINGS; | |
} | |
final String value = property.trim(); | |
if (value.length() == 0) { | |
return EMPTY_STRINGS; | |
} | |
return value.split("\\s*,\\s*"); | |
} | |
private static List<String> getStringCsvList(final Properties properties, final String key) { | |
return new ArrayList<>(Arrays.asList(getStringCsvArray(properties, key))); | |
} | |
private static void printError(final String format, final Object... args) { | |
System.err.printf(format, args); | |
} | |
private static void safeClose(final Closeable stream) { | |
if (stream != null) try { | |
stream.close(); | |
} catch (Exception e) { | |
// can't do anything about it | |
} | |
} | |
private static boolean notEqual(final ValueExpression<String> newValue, final ValueExpression<String> currentValue) { | |
if (newValue == null) { | |
return currentValue.getResolvedValue() != null; | |
} | |
return !Objects.equals(newValue.getValue(), currentValue.getValue()); | |
} | |
private static boolean notEqual(final String newValue, final ValueExpression<String> currentValue) { | |
if (newValue == null) { | |
return currentValue.getResolvedValue() != null; | |
} | |
if (currentValue.isExpression()) { | |
final String resolvedCurrentValue = currentValue.getResolvedValue(); | |
final String resolvedNewValue = ValueExpression.STRING_RESOLVER.resolve(newValue).getResolvedValue(); | |
return resolvedCurrentValue == null ? resolvedNewValue != null : !resolvedCurrentValue.equals(resolvedNewValue); | |
} | |
return !newValue.equals(currentValue.getValue()); | |
} | |
private static boolean booleanNotEqual(final String newValue, final ValueExpression<Boolean> currentValue) { | |
if (newValue == null) { | |
return currentValue.getResolvedValue() != null; | |
} | |
if (currentValue.isExpression()) { | |
final Boolean resolvedCurrentValue = currentValue.getResolvedValue(); | |
final Boolean resolvedNewValue = ValueExpression.BOOLEAN_RESOLVER.resolve(newValue).getResolvedValue(); | |
return resolvedCurrentValue == null ? resolvedNewValue != null : !resolvedCurrentValue.equals(resolvedNewValue); | |
} | |
return !newValue.equals(currentValue.getValue()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment