View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.servlet;
20  
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  
26  import javax.servlet.ServletContext;
27  import javax.servlet.ServletException;
28  import javax.servlet.http.HttpServletRequest;
29  
30  import org.eclipse.jetty.server.Dispatcher;
31  import org.eclipse.jetty.server.handler.ContextHandler;
32  import org.eclipse.jetty.server.handler.ErrorHandler;
33  
34  /* ------------------------------------------------------------ */
35  /** Error Page Error Handler
36   *
37   * An ErrorHandler that maps exceptions and status codes to URIs for dispatch using
38   * the internal ERROR style of dispatch.
39   *
40   */
41  public class ErrorPageErrorHandler extends ErrorHandler implements ErrorHandler.ErrorPageMapper
42  {
43      public final static String GLOBAL_ERROR_PAGE = "org.eclipse.jetty.server.error_page.global";
44  
45      protected ServletContext _servletContext;
46      private final Map<String,String> _errorPages= new HashMap<String,String>(); // code or exception to URL
47      private final List<ErrorCodeRange> _errorPageList=new ArrayList<ErrorCodeRange>(); // list of ErrorCode by range
48  
49      /* ------------------------------------------------------------ */
50      public ErrorPageErrorHandler()
51      {}
52  
53      /* ------------------------------------------------------------ */
54      @Override
55      public String getErrorPage(HttpServletRequest request)
56      {
57          String error_page= null;
58  
59          Throwable th= (Throwable)request.getAttribute(Dispatcher.ERROR_EXCEPTION);
60  
61          // Walk the cause hierarchy
62          while (error_page == null && th != null )
63          {
64              Class<?> exClass=th.getClass();
65              error_page= (String)_errorPages.get(exClass.getName());
66  
67              // walk the inheritance hierarchy
68              while (error_page == null)
69              {
70                  exClass= exClass.getSuperclass();
71                  if (exClass==null)
72                      break;
73                  error_page= (String)_errorPages.get(exClass.getName());
74              }
75  
76              th=(th instanceof ServletException)?((ServletException)th).getRootCause():null;
77          }
78  
79          if (error_page == null)
80          {
81              // look for an exact code match
82              Integer code=(Integer)request.getAttribute(Dispatcher.ERROR_STATUS_CODE);
83              if (code!=null)
84              {
85                  error_page= (String)_errorPages.get(Integer.toString(code));
86  
87                  // if still not found
88                  if ((error_page == null) && (_errorPageList != null))
89                  {
90                      // look for an error code range match.
91                      for (int i = 0; i < _errorPageList.size(); i++)
92                      {
93                          ErrorCodeRange errCode = (ErrorCodeRange) _errorPageList.get(i);
94                          if (errCode.isInRange(code))
95                          {
96                              error_page = errCode.getUri();
97                              break;
98                          }
99                      }
100                 }
101             }
102         }
103 
104         //try servlet 3.x global error page
105         if (error_page == null)
106             error_page = _errorPages.get(GLOBAL_ERROR_PAGE);
107         
108         return error_page;
109     }
110 
111 
112     /* ------------------------------------------------------------ */
113     /**
114      * @return Returns the errorPages.
115      */
116     public Map<String,String> getErrorPages()
117     {
118         return _errorPages;
119     }
120 
121     /* ------------------------------------------------------------ */
122     /**
123      * @param errorPages The errorPages to set. A map of Exception class name  or error code as a string to URI string
124      */
125     public void setErrorPages(Map<String,String> errorPages)
126     {
127         _errorPages.clear();
128         if (errorPages!=null)
129             _errorPages.putAll(errorPages);
130     }
131 
132     /* ------------------------------------------------------------ */
133     /** Add Error Page mapping for an exception class
134      * This method is called as a result of an exception-type element in a web.xml file
135      * or may be called directly
136      * @param exception The exception
137      * @param uri The URI of the error page.
138      */
139     public void addErrorPage(Class<? extends Throwable> exception,String uri)
140     {
141         _errorPages.put(exception.getName(),uri);
142     }
143 
144     /* ------------------------------------------------------------ */
145     /** Add Error Page mapping for an exception class
146      * This method is called as a result of an exception-type element in a web.xml file
147      * or may be called directly
148      * @param exceptionClassName The exception
149      * @param uri The URI of the error page.
150      */
151     public void addErrorPage(String exceptionClassName,String uri)
152     {
153         _errorPages.put(exceptionClassName,uri);
154     }
155 
156     /* ------------------------------------------------------------ */
157     /** Add Error Page mapping for a status code.
158      * This method is called as a result of an error-code element in a web.xml file
159      * or may be called directly
160      * @param code The HTTP status code to match
161      * @param uri The URI of the error page.
162      */
163     public void addErrorPage(int code,String uri)
164     {
165         _errorPages.put(Integer.toString(code),uri);
166     }
167 
168     /* ------------------------------------------------------------ */
169     /** Add Error Page mapping for a status code range.
170      * This method is not available from web.xml and must be called
171      * directly.
172      * @param from The lowest matching status code
173      * @param to The highest matching status code
174      * @param uri The URI of the error page.
175      */
176     public void addErrorPage(int from, int to, String uri)
177     {
178         _errorPageList.add(new ErrorCodeRange(from, to, uri));
179     }
180 
181     /* ------------------------------------------------------------ */
182     @Override
183     protected void doStart() throws Exception
184     {
185         super.doStart();
186         _servletContext=ContextHandler.getCurrentContext();
187     }
188 
189     /* ------------------------------------------------------------ */
190     /* ------------------------------------------------------------ */
191     private class ErrorCodeRange
192     {
193         private int _from;
194         private int _to;
195         private String _uri;
196 
197         ErrorCodeRange(int from, int to, String uri)
198             throws IllegalArgumentException
199         {
200             if (from > to)
201                 throw new IllegalArgumentException("from>to");
202 
203             _from = from;
204             _to = to;
205             _uri = uri;
206         }
207 
208         boolean isInRange(int value)
209         {
210             if ((value >= _from) && (value <= _to))
211             {
212                 return true;
213             }
214 
215             return false;
216         }
217 
218         String getUri()
219         {
220             return _uri;
221         }
222 
223         @Override
224         public String toString()
225         {
226             return "from: " + _from + ",to: " + _to + ",uri: " + _uri;
227         }
228     }
229 }