/*
* #%L
* ACS AEM Commons Bundle
* %%
* Copyright (C) 2013 - 2015 Adobe
* %%
* 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.
* #L%
*/
package com.adobe.acs.commons.http.headers.impl;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.jackrabbit.oak.commons.PropertiesUtil;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
/**
* Abstract class to handle standard logic for registering a Dispatcher TTL header filter.
*/
public abstract class AbstractDispatcherCacheHeaderFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(AbstractDispatcherCacheHeaderFilter.class);
public static final String PROP_FILTER_PATTERN = "filter.pattern";
protected static final String SERVER_AGENT_NAME = "Server-Agent";
protected static final String DISPATCHER_AGENT_HEADER_VALUE = "Communique-Dispatcher";
private List<ServiceRegistration> filterRegistrations = new ArrayList<ServiceRegistration>();
/**
* Get the value to place in the Cache-Control header.
*
* @return the value of the Cache-Control header
*/
protected abstract String getHeaderName();
/**
* Get the value to place in the Cache-Control header.
*
* @return the value of the Cache-Control header
*/
protected abstract String getHeaderValue();
/*
* Allow sub-classes to process their own activation logic.
*/
protected abstract void doActivate(ComponentContext context) throws Exception;
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
}
@Override
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
if (!(servletRequest instanceof HttpServletRequest) || !(servletResponse instanceof HttpServletResponse)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
if (this.accepts(request)) {
String header = getHeaderName();
String val = getHeaderValue();
log.debug("Adding header {}: {}", header, val);
response.addHeader(header, val);
}
filterChain.doFilter(request, response);
}
@Override
public void destroy() {
}
@SuppressWarnings("unchecked")
protected boolean accepts(final HttpServletRequest request) {
Enumeration<String> agentsEnum = request.getHeaders(SERVER_AGENT_NAME);
List<String> serverAgents = agentsEnum != null ? Collections.list(agentsEnum) : Collections.<String>emptyList();
// Only inject when:
// - GET request
// - No Params
// - From Dispatcher
if (StringUtils.equalsIgnoreCase("get", request.getMethod()) &&
request.getParameterMap().isEmpty() &&
serverAgents.contains(DISPATCHER_AGENT_HEADER_VALUE)) {
return true;
}
return false;
}
@Activate
protected final void activate(ComponentContext context) throws Exception {
Dictionary<?, ?> properties = context.getProperties();
doActivate(context);
String[] filters = PropertiesUtil.toStringArray(properties.get(PROP_FILTER_PATTERN));
if (filters == null || filters.length == 0) {
throw new ConfigurationException(PROP_FILTER_PATTERN, "At least one filter pattern must be specified.");
}
for (String pattern : filters) {
Dictionary<String, String> filterProps = new Hashtable<String, String>();
log.debug("Adding filter ({}) to pattern: {}", this.toString(), pattern);
filterProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_FILTER_REGEX, pattern);
filterProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT, "(" + HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME + "=*)");
ServiceRegistration filterReg = context.getBundleContext().registerService(Filter.class.getName(), this, filterProps);
filterRegistrations.add(filterReg);
}
}
@Deactivate
protected final void deactivate(ComponentContext context) {
for(Iterator<ServiceRegistration> it = filterRegistrations.iterator(); it.hasNext(); ) {
ServiceRegistration registration = it.next();
registration.unregister();
it.remove();
}
}
}