001    // Copyright 2006, 2008, 2010 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    // http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry5.internal.services;
016    
017    import java.io.IOException;
018    import java.net.URLEncoder;
019    
020    import javax.servlet.http.HttpServletResponse;
021    
022    import org.apache.tapestry5.SymbolConstants;
023    import org.apache.tapestry5.internal.structure.Page;
024    import org.apache.tapestry5.ioc.annotations.Symbol;
025    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
026    import org.apache.tapestry5.services.ExceptionReporter;
027    import org.apache.tapestry5.services.RequestExceptionHandler;
028    import org.apache.tapestry5.services.Response;
029    import org.slf4j.Logger;
030    
031    /**
032     * Default implementation of {@link RequestExceptionHandler} that displays the standard ExceptionReport page. The page
033     * must implement the {@link ExceptionReporter} interface.
034     */
035    public class DefaultRequestExceptionHandler implements RequestExceptionHandler
036    {
037        private final RequestPageCache pageCache;
038    
039        private final PageResponseRenderer renderer;
040    
041        private final Logger logger;
042    
043        private final String pageName;
044    
045        private final Response response;
046    
047        public DefaultRequestExceptionHandler(RequestPageCache pageCache, PageResponseRenderer renderer, Logger logger,
048    
049        @Symbol(SymbolConstants.EXCEPTION_REPORT_PAGE)
050        String pageName,
051    
052        Response response)
053        {
054            this.pageCache = pageCache;
055            this.renderer = renderer;
056            this.logger = logger;
057            this.pageName = pageName;
058            this.response = response;
059        }
060    
061        public void handleRequestException(Throwable exception) throws IOException
062        {
063            logger.error(ServicesMessages.requestException(exception), exception);
064    
065            // TAP5-233: Make sure the client knows that an error occurred.
066    
067            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
068    
069            String rawMessage = InternalUtils.toMessage(exception);
070    
071            // Encode it compatibly with the JavaScript escape() function.
072    
073            String encoded = URLEncoder.encode(rawMessage, "UTF-8").replace("+", "%20");
074    
075            response.setHeader("X-Tapestry-ErrorMessage", encoded);
076    
077            Page page = pageCache.get(pageName);
078    
079            ExceptionReporter rootComponent = (ExceptionReporter) page.getRootComponent();
080    
081            // Let the page set up for the new exception.
082    
083            rootComponent.reportException(exception);
084    
085            renderer.renderPageResponse(page);
086        }
087    }