blob: 067a1f995de89dd0e682da4934c318b057323cc6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 com.opensymphony.xwork2.config;
import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
import com.opensymphony.xwork2.config.providers.XWorkConfigurationProvider;
import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* ConfigurationManager - central for XWork Configuration management, including
* its ConfigurationProvider.
*
* @author Jason Carreira
* @author tm_jee
* @version $Date$ $Id$
*/
public class ConfigurationManager {
protected static final Logger LOG = LogManager.getLogger(ConfigurationManager.class);
protected Configuration configuration;
protected Lock providerLock = new ReentrantLock();
private List<ContainerProvider> containerProviders = new CopyOnWriteArrayList<>();
private List<PackageProvider> packageProviders = new CopyOnWriteArrayList<>();
protected String defaultFrameworkBeanName;
private boolean providersChanged = false;
private boolean reloadConfigs = true; // for the first time
public ConfigurationManager(String name) {
this.defaultFrameworkBeanName = name;
}
/**
* @return the current XWork configuration object. By default an instance of DefaultConfiguration will be returned
*
* @see com.opensymphony.xwork2.config.impl.DefaultConfiguration
*/
public synchronized Configuration getConfiguration() {
if (configuration == null) {
setConfiguration(createConfiguration(defaultFrameworkBeanName));
try {
configuration.reloadContainer(getContainerProviders());
} catch (ConfigurationException e) {
setConfiguration(null);
throw new ConfigurationException("Unable to load configuration.", e);
}
} else {
conditionalReload();
}
return configuration;
}
protected Configuration createConfiguration(String beanName) {
return new DefaultConfiguration(beanName);
}
public synchronized void setConfiguration(Configuration configuration) {
this.configuration = configuration;
}
/**
* <p>
* Get the current list of ConfigurationProviders. If no custom ConfigurationProviders have been added, this method
* will return a list containing only the default ConfigurationProvider, XMLConfigurationProvider. If a custom
* ConfigurationProvider has been added, then the XmlConfigurationProvider must be added by hand.
* </p>
*
* <p>
* TODO: The lazy instantiation of XmlConfigurationProvider should be refactored to be elsewhere. The behavior described above seems unintuitive.
* </p>
*
* @return the list of registered ConfigurationProvider objects
* @see ConfigurationProvider
*/
public List<ContainerProvider> getContainerProviders() {
providerLock.lock();
try {
if (containerProviders.size() == 0) {
containerProviders.add(new XWorkConfigurationProvider());
containerProviders.add(new XmlConfigurationProvider("xwork.xml", false));
}
return containerProviders;
} finally {
providerLock.unlock();
}
}
/**
* Set the list of configuration providers
*
* @param containerProviders list of {@link ConfigurationProvider} to be set
*/
public void setContainerProviders(List<ContainerProvider> containerProviders) {
providerLock.lock();
try {
this.containerProviders = new CopyOnWriteArrayList<>(containerProviders);
providersChanged = true;
} finally {
providerLock.unlock();
}
}
/**
* adds a configuration provider to the List of ConfigurationProviders. a given ConfigurationProvider may be added
* more than once
*
* @param provider the ConfigurationProvider to register
*/
public void addContainerProvider(ContainerProvider provider) {
if (!containerProviders.contains(provider)) {
containerProviders.add(provider);
providersChanged = true;
}
}
public void clearContainerProviders() {
for (ContainerProvider containerProvider : containerProviders) {
clearContainerProvider(containerProvider);
}
containerProviders.clear();
providersChanged = true;
}
private void clearContainerProvider(ContainerProvider containerProvider) {
try {
containerProvider.destroy();
} catch (Exception e) {
LOG.warn("Error while destroying container provider [{}]", containerProvider.toString(), e);
}
}
/**
* Destroy its managing Configuration instance
*/
public synchronized void destroyConfiguration() {
clearContainerProviders(); // let's destroy the ConfigurationProvider first
containerProviders = new CopyOnWriteArrayList<ContainerProvider>();
if (configuration != null)
configuration.destroy(); // let's destroy it first, before nulling it.
configuration = null;
}
/**
* Reloads the Configuration files if the configuration files indicate that they need to be reloaded.
*/
public synchronized void conditionalReload() {
if (reloadConfigs || providersChanged) {
LOG.debug("Checking ConfigurationProviders for reload.");
List<ContainerProvider> providers = getContainerProviders();
boolean reload = needReloadContainerProviders(providers);
if (!reload) {
reload = needReloadPackageProviders();
}
if (reload) {
reloadProviders(providers);
}
updateReloadConfigsFlag();
providersChanged = false;
}
}
private void updateReloadConfigsFlag() {
reloadConfigs = Boolean.parseBoolean(configuration.getContainer().getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD));
if (LOG.isDebugEnabled()) {
LOG.debug("Updating [{}], current value is [{}], new value [{}]",
StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, String.valueOf(reloadConfigs), String.valueOf(reloadConfigs));
}
}
private boolean needReloadPackageProviders() {
if (packageProviders != null) {
for (PackageProvider provider : packageProviders) {
if (provider.needsReload()) {
LOG.info("Detected package provider [{}] needs to be reloaded. Reloading all providers.", provider);
return true;
}
}
}
return false;
}
private boolean needReloadContainerProviders(List<ContainerProvider> providers) {
for (ContainerProvider provider : providers) {
if (provider.needsReload()) {
LOG.info("Detected container provider [{}] needs to be reloaded. Reloading all providers.", provider);
return true;
}
}
return false;
}
private void reloadProviders(List<ContainerProvider> providers) {
for (ContainerProvider containerProvider : containerProviders) {
try {
containerProvider.destroy();
} catch (Exception e) {
LOG.warn("error while destroying configuration provider [{}]", containerProvider, e);
}
}
packageProviders = this.configuration.reloadContainer(providers);
}
public synchronized void reload() {
packageProviders = getConfiguration().reloadContainer(getContainerProviders());
}
}