grails.plugin.errorpagesfix.PatchedErrorHandlingServlet.java Source code

Java tutorial

Introduction

Here is the source code for grails.plugin.errorpagesfix.PatchedErrorHandlingServlet.java

Source

/*
 * Copyright 2010 Luke Daley
 *
 * 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 grails.plugin.errorpagesfix;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Collections;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.codehaus.groovy.grails.web.errors.GrailsExceptionResolver;
import org.codehaus.groovy.grails.web.errors.GrailsWrappedRuntimeException;
import org.codehaus.groovy.grails.web.mapping.UrlMappingInfo;
import org.codehaus.groovy.grails.web.mapping.UrlMappingsHolder;
import org.codehaus.groovy.grails.web.mapping.exceptions.UrlMappingException;
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest;
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter;
import org.codehaus.groovy.grails.web.servlet.mvc.exceptions.ControllerExecutionException;
import org.codehaus.groovy.grails.web.sitemesh.FactoryHolder;
import org.codehaus.groovy.grails.web.util.IncludeResponseWrapper;
import org.codehaus.groovy.grails.web.util.WebUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;

import org.codehaus.groovy.grails.web.servlet.*;

/**
 * Copy of the ErrorHandlingServlet in Grails, but changed to use forwards instead of includes.
 * It also does not do manual layout decoration as it expects the sitemesh filter to do that.
 * 
 * @see GRAILS-6992
 */
public class PatchedErrorHandlingServlet extends GrailsDispatcherServlet {

    private static final long serialVersionUID = 8792197458391395589L;
    private static final String TEXT_HTML = "text/html";
    private static final String GSP_SUFFIX = ".gsp";
    private static final String JSP_SUFFIX = ".jsp";

    @Override
    protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
        return request; // ignore multipart requests when an error occurs
    }

    @Override
    protected void doDispatch(final HttpServletRequest request, final HttpServletResponse response)
            throws Exception {
        int statusCode;

        if (request.getAttribute("javax.servlet.error.status_code") != null) {
            statusCode = Integer.parseInt(request.getAttribute("javax.servlet.error.status_code").toString());
        } else {
            statusCode = 500;
        }

        Throwable t = null;
        if (request.getAttribute("javax.servlet.error.exception") != null) {
            t = (Throwable) request.getAttribute("javax.servlet.error.exception");
            if (!(t instanceof GrailsWrappedRuntimeException) && request.getAttribute("exception") == null) {
                request.setAttribute("exception", new GrailsWrappedRuntimeException(getServletContext(), t));
            }
        }
        final UrlMappingsHolder urlMappingsHolder = lookupUrlMappings();
        UrlMappingInfo matchedInfo = null;
        if (t != null) {
            matchedInfo = urlMappingsHolder.matchStatusCode(statusCode, t);
            if (matchedInfo == null) {
                matchedInfo = urlMappingsHolder.matchStatusCode(statusCode,
                        GrailsExceptionResolver.getRootCause(t));
            }
        }

        if (matchedInfo == null) {
            matchedInfo = urlMappingsHolder.matchStatusCode(statusCode);
        }
        final UrlMappingInfo urlMappingInfo = matchedInfo;

        if (urlMappingInfo != null) {
            final GrailsWebRequest webRequest = (GrailsWebRequest) RequestContextHolder.getRequestAttributes();
            request.setAttribute("com.opensymphony.sitemesh.APPLIED_ONCE", null);
            urlMappingInfo.configure(webRequest);

            String viewName = urlMappingInfo.getViewName();
            if (viewName == null || viewName.endsWith(GSP_SUFFIX) || viewName.endsWith(JSP_SUFFIX)) {
                WebUtils.forwardRequestForUrlMappingInfo(request, response, urlMappingInfo, Collections.EMPTY_MAP);
            } else {
                ViewResolver viewResolver = WebUtils.lookupViewResolver(getServletContext());
                if (viewResolver != null) {
                    View v;
                    try {
                        v = WebUtils.resolveView(request, urlMappingInfo, viewName, viewResolver);
                        IncludeResponseWrapper includeResponse = new IncludeResponseWrapper(response);
                        v.render(Collections.EMPTY_MAP, request, response);
                    } catch (Exception e) {
                        throw new UrlMappingException(
                                "Error mapping onto view [" + viewName + "]: " + e.getMessage(), e);
                    }
                }
            }
        } else {
            renderDefaultResponse(response, statusCode);
        }
    }

    private void renderDefaultResponse(HttpServletResponse response, int statusCode) throws IOException {
        if (statusCode == 404) {
            renderDefaultResponse(response, statusCode, "Not Found", "Page not found.");
        } else {
            renderDefaultResponse(response, statusCode, "Internal Error", "Internal server error.");
        }
    }

    private void renderDefaultResponse(HttpServletResponse response, int statusCode, String title, String text)
            throws IOException {
        response.setStatus(HttpServletResponse.SC_NOT_FOUND);
        response.setContentType(TEXT_HTML);

        Writer writer = response.getWriter();

        writer.write("<HTML>\n<HEAD>\n<TITLE>Error " + statusCode + " - " + title);
        writer.write("</TITLE>\n<BODY>\n<H2>Error " + statusCode + " - " + title + ".</H2>\n");
        writer.write(text + "<BR/>");

        for (int i = 0; i < 20; i++) {
            writer.write("\n<!-- Padding for IE                  -->");
        }

        writer.write("\n</BODY>\n</HTML>\n");
        writer.flush();
    }

    private UrlMappingsHolder lookupUrlMappings() {
        WebApplicationContext wac = WebApplicationContextUtils
                .getRequiredWebApplicationContext(getServletContext());
        return (UrlMappingsHolder) wac.getBean(UrlMappingsHolder.BEAN_ID);
    }
}