com.scooterframework.web.controller.ScooterRequestFilter.java Source code

Java tutorial

Introduction

Here is the source code for com.scooterframework.web.controller.ScooterRequestFilter.java

Source

/*
 *   This software is distributed under the terms of the FSF 
 *   Gnu Lesser General Public License (see lgpl.txt). 
 *
 *   This program is distributed WITHOUT ANY WARRANTY. See the
 *   GNU General Public License for more details.
 */
package com.scooterframework.web.controller;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;

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 javax.servlet.http.HttpServletResponseWrapper;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.scooterframework.admin.Constants;
import com.scooterframework.admin.EnvConfig;
import com.scooterframework.common.exception.FileUploadException;
import com.scooterframework.common.logging.LogUtil;
import com.scooterframework.common.util.CurrentThreadCache;
import com.scooterframework.common.util.CurrentThreadCacheClient;
import com.scooterframework.web.route.RequestInfo;

/**
 * ScooterRequestFilter can be attached to either an individual servlet
 * or to a URL pattern.  This filter performs the following functions:
 * <ul>
 * <li>Loads property value under the attribute name
 *     defined by the value of the <tt>attribute</tt> initialization
 *     parameter.</li>
 * <li>Initializes WebActionContext.</li>
 * <li>Records a bench mark in the response header if specified in environment.properties file.</li>
 * <li>Cleans up content cached in the request thread.</li>
 * </ul>
 * 
 * <p>The following parameters are allowed to configure this filter in web.xml:</p>
 * <pre>
 *   Examples:
 *     excluded_paths: /images, /javascripts, /layouts, /stylesheets, /css
 *           encoding: UTF-8
 * </pre>
 * 
 * @author (Fei) John Chen
 */
public class ScooterRequestFilter implements Filter {
    /**
     * Directory paths that we want this filter to skip.
     */
    protected String excludedPaths = null;

    /**
     * Character encoding to be used.
     */
    protected String encoding = null;

    /**
     * Place this filter into service.
     *
     * @param filterConfig The filter configuration object
     */
    public void init(FilterConfig filterConfig) throws ServletException {
        this.excludedPaths = filterConfig.getInitParameter("excluded_paths");
        this.encoding = filterConfig.getInitParameter("encoding");

        otherInit();
    }

    protected void otherInit() {
        //Do something more
    }

    /**
     * Take this filter out of service.
     */
    public void destroy() {
        this.excludedPaths = null;
    }

    /**
     * Time the processing that is performed by all subsequent filters in the
     * current filter stack, including the ultimately invoked servlet.
     *
     * @param request The servlet request we are processing
     * @param chain The filter chain we are processing
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet error occurs
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        boolean staticContent = isStaticContentRequest((HttpServletRequest) request);

        if (encoding != null) {
            request.setCharacterEncoding(encoding);
            if (!staticContent) {
                response.setCharacterEncoding(encoding);
            }
        }

        // boolean skip = skippedRequestPath((HttpServletRequest)request);
        boolean skip = staticContent;

        long before = System.currentTimeMillis();

        if (!skip) {
            initializeActionContext((HttpServletRequest) request, (HttpServletResponse) response);
        } else {
            request.setAttribute(Constants.SKIP_PATH, "Y");
        }

        if (isAjaxRequest((HttpServletRequest) request)) {
            request.setAttribute(Constants.SITEMESH_FILTERAPPLIED, Boolean.TRUE);
        }

        String requestPathKeyWithQueryString = requestInfo(skip, (HttpServletRequest) request);
        log.debug("============>>\"" + requestPathKeyWithQueryString + "\"");

        try {
            chain.doFilter(request, response);
        } catch (Throwable ex) {
            log.error("Error from chain.doFilter: " + ex.getMessage(), ex);
        }

        long after = System.currentTimeMillis();

        if (EnvConfig.getInstance().allowRecordBenchmark()) {
            log.info("\"" + requestPathKeyWithQueryString + "\" takes: " + (after - before) + " ms");
            if (EnvConfig.getInstance().allowRecordBenchmarkInHeader()) {
                HttpServletResponseWrapper resw = new HttpServletResponseWrapper((HttpServletResponse) response);
                resw.addHeader("Exec-Time", (after - before) + " ms");
            }
        }

        clearCachedRequestData();
    }

    protected boolean isStaticContentRequest(HttpServletRequest request) {
        String contextPath = request.getContextPath();
        String requestURI = request.getRequestURI();
        String staticPath = contextPath + "/" + "static";
        return (requestURI.startsWith(staticPath)) ? true : false;
    }

    protected String requestInfo(boolean skipStatic, HttpServletRequest request) {
        String method = getRequestMethod(request);
        String requestPath = getRequestPath(request);
        String requestPathKey = RequestInfo.generateRequestKey(requestPath, method);
        String s = requestPathKey;
        String queryString = request.getQueryString();
        if (queryString != null)
            s += "?" + queryString;

        CurrentThreadCacheClient.cacheHttpMethod(method);
        CurrentThreadCacheClient.cacheRequestPath(requestPath);
        CurrentThreadCacheClient.cacheRequestPathKey(requestPathKey);

        if (skipStatic)
            return s;

        //request header
        Properties headers = new Properties();
        Enumeration<?> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = (String) headerNames.nextElement();
            String value = request.getHeader(name);
            if (value != null)
                headers.setProperty(name, value);
        }
        CurrentThreadCache.set(Constants.REQUEST_HEADER, headers);

        if (isLocalRequest(request)) {
            CurrentThreadCache.set(Constants.LOCAL_REQUEST, Constants.VALUE_FOR_LOCAL_REQUEST);
        }

        if (isFileUploadRequest(request)) {
            CurrentThreadCache.set(Constants.FILE_UPLOAD_REQUEST, Constants.VALUE_FOR_FILE_UPLOAD_REQUEST);

            try {
                List<FileItem> files = new ArrayList<FileItem>();
                ServletFileUpload fileUpload = EnvConfig.getInstance().getServletFileUpload();
                List<?> items = fileUpload.parseRequest(request);
                for (Object fi : items) {
                    FileItem item = (FileItem) fi;
                    if (item.isFormField()) {
                        ActionControl.storeToRequest(item.getFieldName(), item.getString());
                    } else if (!item.isFormField() && !"".equals(item.getName())) {
                        files.add(item);
                    }
                }
                CurrentThreadCache.set(Constants.FILE_UPLOAD_REQUEST_FILES, files);
            } catch (Exception ex) {
                CurrentThreadCacheClient.storeError(new FileUploadException(ex));
            }
        }

        return s;
    }

    /**
     * Returns request path of the HttpServletRequest <tt>request</tt>. A 
     * request path is a combination of the <tt>request</tt>'s servletPath and pathInfo. 
     * 
     * @param request HttpServletRequest
     * @return request path
     */
    protected String getRequestPath(HttpServletRequest request) {
        String contextPath = request.getContextPath();
        String requestURI = decode(cleanJsessionid(request.getRequestURI()));
        CurrentThreadCache.set(Constants.REQUEST_URI, requestURI);

        String requestPath = requestURI.substring(contextPath.length());
        if (requestPath.length() > 1 && (requestURI.endsWith("/") || requestURI.endsWith("\\"))) {
            requestPath = requestPath.substring(0, requestPath.length() - 1);
        }
        return requestPath;
    }

    private String decode(String s) {
        String ss = s;
        try {
            ss = URLDecoder.decode(s, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.warn("Failed to decode \"" + s + "\" because " + e.getMessage());
        }
        return ss;
    }

    private static String cleanJsessionid(String requestPath) {
        String s = requestPath;
        if (s.indexOf(";jsessionid") != -1) {
            s = s.substring(0, s.indexOf(";jsessionid"));
        }
        return s;
    }

    /**
     * Returns the method of the <tt>request</tt>.
     */
    protected String getRequestMethod(HttpServletRequest request) {
        String m = request.getParameter(Constants.HTTP_METHOD);
        if (m == null) {
            m = request.getMethod();
        }
        return m.toUpperCase();
    }

    protected boolean isAjaxRequest(HttpServletRequest request) {
        return (request.getParameter(Constants.AJAX_REQUEST) != null) ? true : false;
    }

    /**
     * Cleans up all local cached data to prepare for the next request.
     */
    protected void clearCachedRequestData() {
        CurrentThreadCache.clear();
    }

    protected void initializeActionContext(HttpServletRequest request, HttpServletResponse response) {
        WebActionContext wac = new WebActionContext(request, response);
        ACH.setActionContext(wac);
    }

    /**
     * Checks if a request path must be skipped.
     * 
     * @param request
     * @return true if the request path should be skipped.
     */
    protected boolean skippedRequestPath(HttpServletRequest request) {
        if (excludedPaths == null || "Y".equals(request.getAttribute(Constants.SKIP_PATH)))
            return true;

        String contextPath = request.getContextPath();
        String uriPath = request.getRequestURI();
        String servletPathInfo = "";
        String requestPathDir = uriPath;
        if (uriPath.length() > contextPath.length()) {
            servletPathInfo = uriPath.substring(contextPath.length());
            requestPathDir = servletPathInfo;
            int secondSlashIndex = servletPathInfo.indexOf("/", 1);
            if (secondSlashIndex != -1)
                requestPathDir = servletPathInfo.substring(0, secondSlashIndex);
        }

        boolean status = false;
        if (!"/".equals(requestPathDir) && excludedPaths.indexOf(requestPathDir) != -1) {
            status = true;
        }

        log.debug("skip = " + status + " for " + servletPathInfo);
        return status;
    }

    protected boolean isLocalRequest(HttpServletRequest request) {
        String requestURL = request.getRequestURL().toString();
        String remoteAddr = request.getRemoteAddr();
        String remoteHost = request.getRemoteHost();
        if (requestURL.startsWith(Constants.LOCAL_HOST_URL_PREFIX_1)
                || requestURL.startsWith(Constants.LOCAL_HOST_URL_PREFIX_2)
                || requestURL.startsWith(Constants.LOCAL_HOST_URL_PREFIX_3)
                || requestURL.startsWith(Constants.LOCAL_HOST_URL_PREFIX_4)
                || remoteAddr.equals(Constants.LOCAL_HOST_REMOTE_ADDRESS)
                || remoteHost.equals(Constants.LOCAL_HOST_REMOTE_HOST_1)
                || remoteHost.equals(Constants.LOCAL_HOST_REMOTE_HOST_2)) {
            return true;
        }
        return false;
    }

    protected boolean isFileUploadRequest(HttpServletRequest request) {
        return ServletFileUpload.isMultipartContent(request);
    }

    protected LogUtil log = LogUtil.getLogger(this.getClass().getName());
}