/*******************************************************************************
 * Copyright (c) 2015 Eclipse RDF4J contributors, Aduna, and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Distribution License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *******************************************************************************/
package org.eclipse.rdf4j.workbench.proxy;

import java.io.IOException;

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.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Resource cache expiry filter for Tomcat 6, based on code authored by Saket Kumar.
 *
 * @see <a href="http://bit.ly/tomcat-6-caching">Enable Caching in Tomcat 6</a>
 * @author Dale Visser
 */
public class CacheFilter implements Filter {

	private static final Logger LOGGER = LoggerFactory.getLogger(CacheFilter.class);

	/**
	 * HTTP header key for controlling caching of resources.
	 */
	private final static String CACHE_CONTROL = "Cache-Control";

	/**
	 * Maximum allowed expiry lifetime in seconds, set to one year according to the advice in RFC 2616.
	 *
	 * @see <a href="https://www.ietf.org/rfc/rfc2616.txt">RFC 2616: HTTP/1.1</a>
	 */
	public final static long MAX_EXPIRY = (365 * 24 + 6) * 60 * 60;

	/**
	 * Minimum allowed expiry lifetime, zero, which corresponds to not caching at all.
	 */
	public final static long MIN_EXPIRY = 0;

	private Long expiry = null;

	/**
	 * Set a maximum expiry Cache-Control header applicable to the client and to intermediate caching servers.
	 */
	@Override
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		if (null != expiry) {
			((HttpServletResponse) res).setHeader(CACHE_CONTROL, "max-age=" + expiry + ", public");
		}
		chain.doFilter(req, res);
	}

	/**
	 * Parse the Cache-Control configuration parameter as a long integer, and set the filter expiry value, modulo the
	 * minimum and maximum expiry constraints. If the configuration parameter is not present, or not a valid long
	 * integer value, then no Cache-Control headers will be applied by the filter.
	 *
	 * @see #MIN_EXPIRY
	 * @see #MAX_EXPIRY
	 */
	@Override
	public void init(FilterConfig config) throws ServletException {
		try {
			expiry = Math.min(Math.max(MIN_EXPIRY, Long.parseLong(config.getInitParameter(CACHE_CONTROL))), MAX_EXPIRY);
		} catch (NumberFormatException nfe) {
			LOGGER.warn("Failed to parse " + CACHE_CONTROL + " value.", nfe);
			expiry = null;
		}
	}

	/**
	 * Make stored references available for garbage collection.
	 */
	@Override
	public void destroy() {
		expiry = null;
	}
}
