/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.configuration.easyconf;
import com.germinus.easyconf.AggregatedProperties;
import com.germinus.easyconf.ConfigurationException;
import com.germinus.easyconf.Conventions;
import com.germinus.easyconf.DatasourceURL;
import com.germinus.easyconf.FileConfigurationChangedReloadingStrategy;
import com.germinus.easyconf.JndiURL;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.ReflectionUtil;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.configuration.AbstractFileConfiguration;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.FileConfiguration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.PropertiesConfigurationLayout;
import org.apache.commons.configuration.SubsetConfiguration;
import org.apache.commons.configuration.SystemConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
/**
* @author Raymond Augé
*/
public class ClassLoaderAggregateProperties extends AggregatedProperties {
public ClassLoaderAggregateProperties(
ClassLoader classLoader, String companyId, String componentName) {
super(companyId, componentName);
_classLoader = classLoader;
_companyId = companyId;
_componentName = componentName;
_prefixedSystemConfiguration = new SubsetConfiguration(
_systemConfiguration, _getPrefix(), null);
}
@Override
public void addBaseFileName(String fileName) {
URL url = _classLoader.getResource(fileName);
Configuration configuration = _addPropertiesSource(
fileName, url, _baseCompositeConfiguration);
if (configuration != null) {
_baseConfigurationLoaded = true;
if (configuration.isEmpty() && _log.isDebugEnabled()) {
_log.debug("Empty configuration " + fileName);
}
}
}
@Override
public void addGlobalFileName(String fileName) {
URL url = _classLoader.getResource(fileName);
_addPropertiesSource(fileName, url, _globalCompositeConfiguration);
}
public CompositeConfiguration getBaseConfiguration() {
return _baseCompositeConfiguration;
}
@Override
public String getComponentName() {
return _componentName;
}
@Override
public Object getProperty(String key) {
Object value = null;
if (value == null) {
value = System.getProperty(_getPrefix().concat(key));
}
if (value == null) {
value = _globalCompositeConfiguration.getProperty(
_getPrefix().concat(key));
}
if (value == null) {
value = _globalCompositeConfiguration.getProperty(key);
}
if (value == null) {
value = _baseCompositeConfiguration.getProperty(key);
}
if (value == null) {
value = super.getProperty(key);
}
if (value == null) {
value = System.getProperty(key);
}
if ((value == null) && key.equals(Conventions.COMPANY_ID_PROPERTY)) {
value = _companyId;
}
if ((value == null) &&
key.equals(Conventions.COMPONENT_NAME_PROPERTY)) {
value = _componentName;
}
return value;
}
@Override
public boolean hasBaseConfiguration() {
return _baseConfigurationLoaded;
}
@Override
public List<String> loadedSources() {
return _loadedSources;
}
private Configuration _addDatasourceProperties(String datasourcePath) {
DatasourceURL datasourceURL = new DatasourceURL(
datasourcePath, _companyId, _componentName,
DatasourceURL.PROPERTIES_TABLE);
return datasourceURL.getConfiguration();
}
private Configuration _addFileProperties(
String fileName,
CompositeConfiguration loadedCompositeConfiguration)
throws ConfigurationException {
try {
FileConfiguration newFileConfiguration =
new PropertiesConfiguration(fileName);
URL url = newFileConfiguration.getURL();
if (_log.isDebugEnabled()) {
_log.debug("Adding file " + url);
}
Long delay = _getReloadDelay(
loadedCompositeConfiguration, newFileConfiguration);
if (delay != null) {
FileChangedReloadingStrategy fileChangedReloadingStrategy =
new FileConfigurationChangedReloadingStrategy();
if (_log.isDebugEnabled()) {
_log.debug(
"File " + url + " will be reloaded every " + delay +
" seconds");
}
long milliseconds = delay.longValue() * 1000;
fileChangedReloadingStrategy.setRefreshDelay(milliseconds);
newFileConfiguration.setReloadingStrategy(
fileChangedReloadingStrategy);
}
_addIncludedPropertiesSources(
newFileConfiguration, loadedCompositeConfiguration);
return newFileConfiguration;
}
catch (org.apache.commons.configuration.ConfigurationException ce) {
if (_log.isDebugEnabled()) {
_log.debug("Configuration source " + fileName + " ignored");
}
return null;
}
}
private void _addIncludedPropertiesSources(
Configuration newConfiguration,
CompositeConfiguration loadedCompositeConfiguration) {
CompositeConfiguration tempCompositeConfiguration =
new CompositeConfiguration();
tempCompositeConfiguration.addConfiguration(
_prefixedSystemConfiguration);
tempCompositeConfiguration.addConfiguration(newConfiguration);
tempCompositeConfiguration.addConfiguration(_systemConfiguration);
tempCompositeConfiguration.addProperty(
Conventions.COMPANY_ID_PROPERTY, _companyId);
tempCompositeConfiguration.addProperty(
Conventions.COMPONENT_NAME_PROPERTY, _componentName);
String[] fileNames = tempCompositeConfiguration.getStringArray(
Conventions.INCLUDE_PROPERTY);
ArrayUtil.reverse(fileNames);
for (String fileName : fileNames) {
URL url = null;
try {
url = _classLoader.getResource(fileName);
}
catch (RuntimeException re) {
if (fileName.startsWith("file:/")) {
throw re;
}
fileName = "file:/".concat(fileName);
url = _classLoader.getResource(fileName);
}
_addPropertiesSource(fileName, url, loadedCompositeConfiguration);
}
}
private Configuration _addJNDIProperties(String sourcePath) {
JndiURL jndiURL = new JndiURL(sourcePath, _companyId, _componentName);
return jndiURL.getConfiguration();
}
private Configuration _addPropertiesSource(
String sourceName, URL url,
CompositeConfiguration loadedCompositeConfiguration) {
try {
Configuration newConfiguration = null;
if (DatasourceURL.isDatasource(sourceName)) {
newConfiguration = _addDatasourceProperties(sourceName);
}
else if (JndiURL.isJndi(sourceName)) {
newConfiguration = _addJNDIProperties(sourceName);
}
else if (url != null) {
newConfiguration = _addURLProperties(
url, loadedCompositeConfiguration);
}
else {
newConfiguration = _addFileProperties(
sourceName, loadedCompositeConfiguration);
}
if (newConfiguration == null) {
return newConfiguration;
}
loadedCompositeConfiguration.addConfiguration(newConfiguration);
super.addConfiguration(newConfiguration);
if (newConfiguration instanceof AbstractFileConfiguration) {
AbstractFileConfiguration abstractFileConfiguration =
(AbstractFileConfiguration)newConfiguration;
URL abstractFileConfigurationURL =
abstractFileConfiguration.getURL();
_loadedSources.add(abstractFileConfigurationURL.toString());
}
else {
_loadedSources.add(sourceName);
}
return newConfiguration;
}
catch (Exception e) {
if (_log.isDebugEnabled()) {
_log.debug(
"Configuration source " + sourceName + " ignored: " +
e.getMessage());
}
return null;
}
}
private Configuration _addURLProperties(
URL url, CompositeConfiguration loadedCompositeConfiguration)
throws ConfigurationException {
try {
PropertiesConfiguration propertiesConfiguration =
new PropertiesConfiguration(url);
PropertiesConfigurationLayout propertiesConfigurationLayout =
propertiesConfiguration.getLayout();
try {
Map<String, Object> layoutData =
(Map<String, Object>)_layoutDataField.get(
propertiesConfigurationLayout);
for (Object propertyLayoutData : layoutData.values()) {
_commentField.set(propertyLayoutData, null);
}
}
catch (ReflectiveOperationException roe) {
if (_log.isWarnEnabled()) {
_log.warn(
"Unable to clear out comments from " +
propertiesConfiguration,
roe);
}
}
if (_log.isDebugEnabled()) {
_log.debug("Adding resource " + url);
}
Long delay = _getReloadDelay(
loadedCompositeConfiguration, propertiesConfiguration);
if (delay != null) {
FileChangedReloadingStrategy fileChangedReloadingStrategy =
new FileConfigurationChangedReloadingStrategy();
if (_log.isDebugEnabled()) {
_log.debug(
"Resource " + url + " will be reloaded every " + delay +
" seconds");
}
long milliseconds = delay.longValue() * 1000;
fileChangedReloadingStrategy.setRefreshDelay(milliseconds);
propertiesConfiguration.setReloadingStrategy(
fileChangedReloadingStrategy);
}
_addIncludedPropertiesSources(
propertiesConfiguration, loadedCompositeConfiguration);
return propertiesConfiguration;
}
catch (org.apache.commons.configuration.ConfigurationException ce) {
if (_log.isDebugEnabled()) {
_log.debug("Configuration source " + url + " ignored");
}
return null;
}
}
private String _getPrefix() {
return _componentName.concat(Conventions.PREFIX_SEPARATOR);
}
private Long _getReloadDelay(
CompositeConfiguration loadedCompositeConfiguration,
FileConfiguration newFileConfiguration) {
Long delay = newFileConfiguration.getLong(
Conventions.RELOAD_DELAY_PROPERTY, null);
if (delay == null) {
delay = loadedCompositeConfiguration.getLong(
Conventions.RELOAD_DELAY_PROPERTY, null);
}
return delay;
}
private static final Log _log = LogFactoryUtil.getLog(
ClassLoaderAggregateProperties.class);
private static final Field _commentField;
private static final Field _layoutDataField;
static {
try {
ClassLoader classLoader =
PropertiesConfigurationLayout.class.getClassLoader();
Class<?> propertyLayoutDataClass = classLoader.loadClass(
PropertiesConfigurationLayout.class.getName() +
"$PropertyLayoutData");
_commentField = ReflectionUtil.getDeclaredField(
propertyLayoutDataClass, "comment");
_layoutDataField = ReflectionUtil.getDeclaredField(
PropertiesConfigurationLayout.class, "layoutData");
}
catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
private final CompositeConfiguration _baseCompositeConfiguration =
new CompositeConfiguration();
private boolean _baseConfigurationLoaded;
private final ClassLoader _classLoader;
private final String _companyId;
private final String _componentName;
private final CompositeConfiguration _globalCompositeConfiguration =
new CompositeConfiguration();
private final List<String> _loadedSources = new ArrayList<>();
private final Configuration _prefixedSystemConfiguration;
private final SystemConfiguration _systemConfiguration =
new SystemConfiguration();
}