View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.tobago.context;
21  
22  import org.slf4j.Logger;
23  import org.slf4j.LoggerFactory;
24  
25  import javax.faces.FacesException;
26  import javax.faces.application.FacesMessage;
27  import javax.faces.application.NavigationHandler;
28  import javax.faces.application.ViewExpiredException;
29  import javax.faces.application.ViewHandler;
30  import javax.faces.component.UIViewRoot;
31  import javax.faces.context.ExceptionHandler;
32  import javax.faces.context.ExceptionHandlerWrapper;
33  import javax.faces.context.FacesContext;
34  import javax.faces.event.ExceptionQueuedEvent;
35  import javax.faces.event.ExceptionQueuedEventContext;
36  import javax.faces.event.PhaseId;
37  import javax.faces.event.PreRenderViewEvent;
38  import javax.faces.view.ViewDeclarationLanguage;
39  import javax.servlet.http.HttpServletResponse;
40  import java.io.FileNotFoundException;
41  import java.lang.invoke.MethodHandles;
42  import java.util.Iterator;
43  
44  public class TobagoExceptionHandler extends ExceptionHandlerWrapper {
45  
46    private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
47  
48    private ExceptionHandler wrapped;
49  
50    public TobagoExceptionHandler(final ExceptionHandler wrapped) {
51      this.wrapped = wrapped;
52    }
53  
54    @Override
55    public ExceptionHandler getWrapped() {
56      return wrapped;
57    }
58  
59    @Override
60    public void handle() throws FacesException {
61  
62      final Iterator<ExceptionQueuedEvent> iterator = getUnhandledExceptionQueuedEvents().iterator();
63      while (iterator.hasNext()) {
64        final ExceptionQueuedEvent event = iterator.next();
65        final ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
66        final Throwable cause = this.getWrapped().getRootCause(context.getException());
67        final FacesContext facesContext = FacesContext.getCurrentInstance();
68        final NavigationHandler nav = facesContext.getApplication().getNavigationHandler();
69  
70        if (cause instanceof ViewExpiredException
71            || cause != null && cause.getCause() instanceof ViewExpiredException) {
72          final ViewExpiredException viewExpiredException = (ViewExpiredException)
73              (cause instanceof ViewExpiredException ? cause : cause.getCause());
74          try {
75            facesContext.addMessage(null,
76                new FacesMessage(FacesMessage.SEVERITY_WARN,
77                    "The view has been expired!",
78                    "Please check the given data or try to start from the beginning."));
79            nav.handleNavigation(facesContext, null, viewExpiredException.getViewId());
80            facesContext.renderResponse();
81            LOG.debug("Handling ViewExpiredException on viewId: {}", viewExpiredException.getViewId());
82          } finally {
83            iterator.remove();
84          }
85        } else {
86          try {
87            final boolean error404 = cause instanceof FileNotFoundException
88                || cause != null && cause.getCause() instanceof FileNotFoundException;
89            final FacesMessage message;
90            if (error404) {
91              message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
92                  "The page was not found!",
93                  "The requested page was not found!");
94              facesContext.getExternalContext().setResponseStatus(HttpServletResponse.SC_NOT_FOUND);
95              LOG.warn("Handling 404 exception.");
96            } else {
97              message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
98                  "An unknown error has occurred!",
99                  "An unknown error has occurred!");
100             facesContext.getExternalContext().setResponseStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
101             LOG.warn("Handling 500 exception.", cause);
102           }
103           facesContext.addMessage(null, message);
104           final String viewId = "/tobago/error.xhtml";
105 
106           // when the rendering was not yet started, we can forward to an error page
107           if (event.getContext().getPhaseId().getOrdinal() < PhaseId.RENDER_RESPONSE.getOrdinal()) {
108             nav.handleNavigation(facesContext, null, viewId);
109             facesContext.renderResponse();
110           } else {
111             final HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
112             response.resetBuffer(); // undo rendering, if you can.
113             final ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
114             final ViewDeclarationLanguage vdl = viewHandler.getViewDeclarationLanguage(facesContext, viewId);
115             final UIViewRoot viewRoot = viewHandler.createView(facesContext, viewId);
116             vdl.buildView(facesContext, viewRoot);
117             facesContext.getApplication().publishEvent(facesContext, PreRenderViewEvent.class, viewRoot);
118             vdl.renderView(facesContext, viewRoot);
119             facesContext.responseComplete();
120           }
121         } catch (Exception e) {
122           LOG.error("Exception while exception handling!", e);
123         } finally {
124           iterator.remove();
125         }
126       }
127     }
128     getWrapped().handle();
129   }
130 }