com.jaspersoft.jasperserver.war.StaticFilesCacheControlFilter.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.jasperserver.war.StaticFilesCacheControlFilter.java

Source

/*
 * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com.
 *
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License  as
 * published by the Free Software Foundation, either version 3 of  the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero  General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public  License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.jaspersoft.jasperserver.war;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * The filter adds the following HTTP Response headers to the response if requested resource matches configured type :
 *
 * Pragma: [empty]
 * Cache-Control: max-age=[configured seconds], public
 * Expires: [now + configured seconds]
 *
 * Expected init parameters :
 * name: urlEndsWith
 * value: space separated list of possible URL suffixes, for example : [.js .css .png .gif .jpg]
 *
 * name: expiresAfterAccessInSecs
 * value: expiration time in seconds, for example 86400 (24 hours)
 *
 * User: Andrew Sokolnikov
 * Date: 11/29/12
 */
public class StaticFilesCacheControlFilter implements Filter {

    public static final String URL_ENDS_WITH = "urlEndsWith";
    public static final String URL_STARTS_WITH = "urlStartsWith";
    public static final String EXCLUDE_PAGE_FROM_CACHE_REGEX = "excludePageFromCacheRegex";
    public static final String EXPIRES_AFTER_ACCESS_IN_SECS = "expiresAfterAccessInSecs";
    public static final String DATE_FORMAT_PATTERN = "EEE, d MMM yyyy HH:mm:ss z";

    // All HTTP dates are in english.
    private static final DateFormat DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT_PATTERN, Locale.ENGLISH);

    // All HTTP date/time stamps MUST be represented in Greenwich Mean Time (GMT), without exception.
    // See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1
    private static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
    static {
        DATE_FORMAT.setTimeZone(GMT_ZONE);
    }

    private static final Log log = LogFactory.getLog(StaticFilesCacheControlFilter.class);

    private Set<String> urlSuffixes = new HashSet<String>();
    private Set<String> urlPrefixes = new HashSet<String>();
    private Set<String> exclusionRegexSet = new HashSet<String>();
    private int expiresInSecs = 0;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Enumeration<String> paramNames = filterConfig.getInitParameterNames();
        while (paramNames != null && paramNames.hasMoreElements()) {
            String paramName = paramNames.nextElement();
            String value = filterConfig.getInitParameter(paramName);
            if (URL_ENDS_WITH.equals(paramName)) {
                if (value != null && value.length() > 0) {
                    String[] types = value.split(" ");
                    for (int i = 0; i < types.length; i++) {
                        if (types[i].length() > 0) {
                            urlSuffixes.add(types[i].toLowerCase());
                            log.debug("URL suffix added : " + types[i]);
                        }
                    }
                }
            } else if (URL_STARTS_WITH.equals(paramName)) {
                if (value != null && value.length() > 0) {
                    String[] types = value.split(" ");
                    for (int i = 0; i < types.length; i++) {
                        if (types[i].length() > 0) {
                            urlPrefixes.add(types[i].toLowerCase());
                            log.debug("URL prefix added : " + types[i]);
                        }
                    }
                }
            } else if (EXCLUDE_PAGE_FROM_CACHE_REGEX.equals(paramName)) {
                if (value == null)
                    continue;
                String[] regexStrs = value.split(" ");
                exclusionRegexSet.addAll(Arrays.asList(regexStrs));
                log.debug("Added " + exclusionRegexSet.size() + " cache exclusion regex.");
            } else if (EXPIRES_AFTER_ACCESS_IN_SECS.equals(paramName)) {
                try {
                    expiresInSecs = Integer.parseInt(value);
                    log.debug("Expires in seconds set : " + expiresInSecs);
                } catch (Exception ex) {
                    log.error(EXPIRES_AFTER_ACCESS_IN_SECS + " should be a non-negative integer", ex);
                }
            } else {
                log.warn("Unknown parameter, ignoring : " + paramName);
            }
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        if (request instanceof HttpServletRequest) {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            HttpServletResponse httpServletResponse = (HttpServletResponse) response;
            String path = httpServletRequest.getServletPath();
            if (path != null) {
                String resourcePatch = httpServletRequest.getPathInfo() == null ? path
                        : path.concat(httpServletRequest.getPathInfo());

                boolean excludeFromCacheFlag = false;
                for (String exclRegex : exclusionRegexSet) {
                    if (path.matches(exclRegex)) {
                        log.debug("Excluding the path from browser cache by not setting the response header: "
                                + path);
                        excludeFromCacheFlag = true;
                        break;
                    }
                }

                if (!excludeFromCacheFlag) {
                    boolean set = false;
                    for (String suffix : urlSuffixes) {
                        if (path.toLowerCase().endsWith(suffix)) {
                            log.debug("Setting headers for " + path);
                            setHeaders(httpServletRequest, httpServletResponse);
                            set = true;
                            break;
                        }
                    }
                    if (!set) {
                        for (String prefix : urlPrefixes) {
                            if (resourcePatch.toLowerCase().startsWith(prefix)) {
                                log.debug("Setting headers for " + resourcePatch);
                                setHeaders(httpServletRequest, httpServletResponse);
                                break;
                            }
                        }
                    }
                }
            }
        }

        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }

    private void setHeaders(HttpServletRequest request, HttpServletResponse response) {
        try {
            response.setHeader("Cache-Control", "max-age=" + expiresInSecs + ", public");
            response.setHeader("Pragma", "");
            response.setHeader("Expires",
                    DATE_FORMAT.format(new Date(new Date().getTime() + expiresInSecs * 1000)));

        } catch (Exception ex) {
            log.warn("Cannot set cache headers", ex);
        }
    }
}