/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE file at the root of the source
* tree and available online at
*
* https://github.com/keeps/roda
*/
package org.roda.wui.filter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang3.StringUtils;
import org.roda.core.RodaCoreFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A filter that can be turned on/off using RODA configuration file.
*/
public class OnOffFilter implements Filter {
/**
* Logger.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(OnOffFilter.class);
/**
* Inner filter class parameter name.
*/
private static final String PARAM_INNER_FILTER_CLASS = "inner-filter-class";
/**
* Configuration values prefix parameter name.
*/
private static final String PARAM_CONFIG_PREFIX = "config-prefix";
/**
* Inner filter to which all calls to this filter will be delegated.
*/
private Filter innerFilter = null;
/**
* This filter is ON?
*/
private Boolean isOn = null;
/**
* The filter configuration from web.xml.
*/
private FilterConfig webXmlFilterConfig = null;
/**
* Combined filter config.
*/
private OnOffFilterConfig filterConfig = null;
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
this.webXmlFilterConfig = filterConfig;
}
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
if (isOn()) {
this.innerFilter.doFilter(servletRequest, servletResponse, filterChain);
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Override
public void destroy() {
if (this.innerFilter != null) {
this.innerFilter.destroy();
}
}
/**
* Is this filter on?
*
* @return <code>true</code> if the Filter is on and <code>false</code>
* otherwise.
* @throws ServletException
* if some error occurs.
*/
private synchronized boolean isOn() throws ServletException {
if (this.isOn == null && isConfigAvailable()) {
initInnerFilter();
}
return this.isOn != null && this.isOn;
}
/**
* Is RODA configuration available?
*
* @return <code>true</code> if RODA configuration is available and
* <code>false</code> otherwise.
*/
private boolean isConfigAvailable() {
return RodaCoreFactory.getRodaConfiguration() != null;
}
/**
* Init inner filter.
*
* @throws ServletException
* if some error occurs.
*/
private void initInnerFilter() throws ServletException {
final Configuration rodaConfig = RodaCoreFactory.getRodaConfiguration();
if (rodaConfig == null) {
LOGGER.info("RODA configuration not available yet. Delaying init of {}.",
this.webXmlFilterConfig.getInitParameter(PARAM_INNER_FILTER_CLASS));
} else {
final String innerFilterClass = this.webXmlFilterConfig.getInitParameter(PARAM_INNER_FILTER_CLASS);
final String configPrefix = this.webXmlFilterConfig.getInitParameter(PARAM_CONFIG_PREFIX);
if (rodaConfig.getBoolean(configPrefix + ".enabled", false)) {
try {
this.innerFilter = (Filter) Class.forName(innerFilterClass).newInstance();
this.innerFilter.init(getFilterConfig());
this.isOn = true;
} catch (final InstantiationException | IllegalAccessException | ClassNotFoundException e) {
this.isOn = false;
throw new ServletException("Error instantiating inner filter - " + e.getMessage(), e);
}
} else {
this.isOn = false;
}
}
LOGGER.info("{} is {}", getFilterConfig().getFilterName(), (this.isOn ? "ON" : "OFF"));
}
/**
* Return the combined filter configuration.
*
* @return the combined filter configuration.
*/
private FilterConfig getFilterConfig() {
if (this.filterConfig == null) {
this.filterConfig = new OnOffFilterConfig(this.webXmlFilterConfig, RodaCoreFactory.getRodaConfiguration());
}
return this.filterConfig;
}
/**
* {@link FilterConfig} implementation that combines web.xml <init-param>
* and RODA configuration values.
*/
private class OnOffFilterConfig implements FilterConfig {
/**
* Default {@link FilterConfig} (from web.xml).
*/
private final FilterConfig filterConfig;
/**
* RODA configuration.
*/
private final Configuration rodaConfig;
/**
* RODA configuration prefix for this filter.
*/
private final String rodaConfigPrefix;
/**
* The list of init parameter names.
*/
private List<String> configNames;
/**
* Constructor.
*
* @param filterConfig
* default filter configuration (from web.xml).
* @param rodaConfig
* RODA configuration.
*/
OnOffFilterConfig(final FilterConfig filterConfig, final Configuration rodaConfig) {
this.filterConfig = filterConfig;
this.rodaConfig = rodaConfig;
final String configPrefix = this.filterConfig.getInitParameter(PARAM_CONFIG_PREFIX);
if (StringUtils.isBlank(configPrefix)) {
this.rodaConfigPrefix = String.format("ui.filter.%s", this.filterConfig.getFilterName());
} else {
this.rodaConfigPrefix = configPrefix;
}
}
@Override
public String getFilterName() {
return this.filterConfig.getFilterName();
}
@Override
public ServletContext getServletContext() {
return this.filterConfig.getServletContext();
}
@Override
public String getInitParameter(final String name) {
String value = getRodaInitParameter(name);
if (value == null) {
value = this.filterConfig.getInitParameter(name);
}
return value;
}
@Override
public Enumeration<String> getInitParameterNames() {
if (this.configNames == null) {
this.configNames = new ArrayList<>();
final Enumeration<String> filterNames = this.filterConfig.getInitParameterNames();
while (filterNames.hasMoreElements()) {
this.configNames.add(filterNames.nextElement());
}
final Iterator<String> rodaNames = this.rodaConfig.getKeys(this.rodaConfigPrefix);
while (rodaNames.hasNext()) {
this.configNames.add(rodaNames.next().replace(this.rodaConfigPrefix + ".", ""));
}
}
return Collections.enumeration(this.configNames);
}
/**
* Get filter init parameter from RODA configuration.
*
* @param name
* the parameter name.
* @return the parameter value.
*/
private String getRodaInitParameter(final String name) {
return this.rodaConfig.getString(this.rodaConfigPrefix + "." + name);
}
}
}