spark.webserver.MatcherFilter.java Source code

Java tutorial

Introduction

Here is the source code for spark.webserver.MatcherFilter.java

Source

/*
 * Copyright 2011- Per Wendel
 * 
 * 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.
 */
package spark.webserver;

import java.io.IOException;
import java.util.List;
import java.util.Set;

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 org.apache.commons.lang.StringUtils;

import com.cinchapi.concourse.util.Logger;
import com.cinchapi.concourse.util.Reflection;

import spark.Access;
import spark.HaltException;
import spark.Request;
import spark.RequestResponseFactory;
import spark.Response;
import spark.Route;
import spark.route.HttpMethod;
import spark.route.RouteMatch;
import spark.route.RouteMatcher;
import spark.webserver.MatcherFilter;
import spark.webserver.NotConsumedException;
import spark.webserver.RequestWrapper;
import spark.webserver.ResponseWrapper;

/**
 * Filter for matching of filters and routes.
 *
 * @author Per Wendel
 */
public class MatcherFilter implements Filter {

    /**
     * Check the path of the {@code servletRequest} and return {@code true} of
     * that path is for a static file.
     * 
     * @param servletRequest
     * @param servletResponse
     * @param chain
     * @return {@code true} if the request is for a static file instead of a
     *         route.
     */
    private static boolean isStaticFileRequest(ServletRequest servletRequest, ServletResponse servletResponse,
            FilterChain chain) {
        String path = Reflection.get("_pathInfo", servletRequest);
        for (String ext : STATIC_FILE_EXTENSIONS) {
            if (path.endsWith(ext)) {
                return true;
            }
        }
        return false;
    }

    private static final String ACCEPT_TYPE_REQUEST_MIME_HEADER = "Accept";
    private static final String INTERNAL_ERROR = "<html><body><h2>500 Internal Error</h2></body></html>";
    private static final String NOT_FOUND = "<html><body><h2>404 Not found</h2>The requested route [%s] has not been mapped in Spark</body></html>";

    /**
     * Valid static file extensions.
     */
    private static final String[] STATIC_FILE_EXTENSIONS = { "jpg", "jpeg", "png", "css", "ico", "gif", "js" };

    private boolean hasOtherHandlers;

    private boolean isServletContext;

    private RouteMatcher routeMatcher;

    /**
     * Constructor
     *
     * @param routeMatcher The route matcher
     * @param isServletContext If true, chain.doFilter will be invoked if
     *            request is not consumed by Spark.
     * @param hasOtherHandlers If true, do nothing if request is not consumed by
     *            Spark in order to let others handlers process the request.
     */
    public MatcherFilter(RouteMatcher routeMatcher, boolean isServletContext, boolean hasOtherHandlers) {
        this.routeMatcher = routeMatcher;
        this.isServletContext = isServletContext;
        this.hasOtherHandlers = hasOtherHandlers;
    }

    public void destroy() {
        // TODO Auto-generated method stub
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, // NOSONAR
            FilterChain chain) throws IOException, ServletException { // NOSONAR
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; // NOSONAR
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;

        String httpMethodStr = httpRequest.getMethod().toLowerCase(); // NOSONAR
        String uri = httpRequest.getRequestURI(); // NOSONAR
        String acceptType = httpRequest.getHeader(ACCEPT_TYPE_REQUEST_MIME_HEADER);

        String bodyContent = null;
        if (!isStaticFileRequest(servletRequest, servletResponse, chain)) {
            RequestWrapper req = new RequestWrapper();
            ResponseWrapper res = new ResponseWrapper();

            try {
                // BEFORE filters
                List<RouteMatch> matchSet = routeMatcher.findTargetsForRequestedRoute(HttpMethod.before, uri,
                        acceptType);

                for (RouteMatch filterMatch : matchSet) {
                    Object filterTarget = filterMatch.getTarget();
                    if (filterTarget instanceof spark.Filter) {
                        Request request = RequestResponseFactory.create(filterMatch, httpRequest);
                        Response response = RequestResponseFactory.create(httpResponse);

                        spark.Filter filter = (spark.Filter) filterTarget;

                        req.setDelegate(request);
                        res.setDelegate(response);

                        filter.handle(req, res);

                        String bodyAfterFilter = Access.getBody(response);
                        if (bodyAfterFilter != null) {
                            bodyContent = bodyAfterFilter;
                        }
                    }
                }
                // BEFORE filters, END

                HttpMethod httpMethod = HttpMethod.valueOf(httpMethodStr);

                RouteMatch match = null;
                match = routeMatcher.findTargetForRequestedRoute(httpMethod, uri, acceptType);

                Object target = null;
                if (match != null) {
                    target = match.getTarget();
                } else if (httpMethod == HttpMethod.head && bodyContent == null) {
                    // See if get is mapped to provide default head mapping
                    bodyContent = routeMatcher.findTargetForRequestedRoute(HttpMethod.get, uri, acceptType) != null
                            ? ""
                            : null;
                } else if (httpMethod == HttpMethod.options && bodyContent == null) {
                    // CON-476: For an OPTIONS request, attempt to get all the
                    // targets for the route and specify those in the response
                    Set<HttpMethod> methods = routeMatcher.findMethodsForRequestedPath(uri, acceptType);
                    if (!methods.isEmpty()) {
                        httpResponse.setHeader("Allow", StringUtils.join(methods, ','));
                        bodyContent = "";
                    }

                }

                if (target != null) {
                    try {
                        String result = null;
                        if (target instanceof Route) {
                            Route route = ((Route) target);
                            Request request = RequestResponseFactory.create(match, httpRequest);
                            Response response = RequestResponseFactory.create(httpResponse);

                            req.setDelegate(request);
                            res.setDelegate(response);

                            Object element = route.handle(req, res);
                            result = route.render(element);
                        }
                        if (result != null) {
                            bodyContent = result;
                        }
                    } catch (HaltException hEx) { // NOSONAR
                        throw hEx; // NOSONAR
                    } catch (Exception e) {
                        Logger.error("", e);
                        httpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                        bodyContent = INTERNAL_ERROR;
                    }
                }

                // AFTER filters
                matchSet = routeMatcher.findTargetsForRequestedRoute(HttpMethod.after, uri, acceptType);

                for (RouteMatch filterMatch : matchSet) {
                    Object filterTarget = filterMatch.getTarget();
                    if (filterTarget instanceof spark.Filter) {
                        Request request = RequestResponseFactory.create(filterMatch, httpRequest);
                        Response response = RequestResponseFactory.create(httpResponse);

                        req.setDelegate(request);
                        res.setDelegate(response);

                        spark.Filter filter = (spark.Filter) filterTarget;
                        filter.handle(req, res);

                        String bodyAfterFilter = Access.getBody(response);
                        if (bodyAfterFilter != null) {
                            bodyContent = bodyAfterFilter;
                        }
                    }
                }
                // AFTER filters, END
            } catch (HaltException hEx) {
                httpResponse.setStatus(hEx.getStatusCode());
                if (hEx.getBody() != null) {
                    bodyContent = hEx.getBody();
                } else {
                    bodyContent = "";
                }
            }
        }

        boolean consumed = bodyContent != null;

        if (!consumed && hasOtherHandlers) {
            throw new NotConsumedException();
        }

        if (!consumed && !isServletContext) {
            httpResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
            bodyContent = String.format(NOT_FOUND, uri);
            consumed = true;
        }

        if (consumed) {
            // Write body content
            if (!httpResponse.isCommitted()) {
                if (httpResponse.getContentType() == null) {
                    httpResponse.setContentType("text/html; charset=utf-8");
                }
                httpResponse.getOutputStream().write(bodyContent.getBytes("utf-8"));
            }
        } else if (chain != null) {
            chain.doFilter(httpRequest, httpResponse);
        }

    }

    public void init(FilterConfig filterConfig) {
        //
    }
}