View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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.RequestDispatcher;
27  import javax.servlet.ServletContext;
28  import javax.servlet.ServletException;
29  import javax.servlet.http.HttpServletRequest;
30  
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      @Override
54      public String getErrorPage(HttpServletRequest request)
55      {
56          String error_page= null;
57          Class<?> exClass= (Class<?>)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE);
58  
59          if (ServletException.class.equals(exClass))
60          {
61              error_page= (String)_errorPages.get(exClass.getName());
62              if (error_page == null)
63              {
64                  Throwable th= (Throwable)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
65                  while (th instanceof ServletException)
66                      th= ((ServletException)th).getRootCause();
67                  if (th != null)
68                      exClass= th.getClass();
69              }
70          }
71  
72          while (error_page == null && exClass != null )
73          {
74              error_page= (String)_errorPages.get(exClass.getName());
75              exClass= exClass.getSuperclass();
76          }
77  
78          if (error_page == null)
79          {
80              // look for an exact code match
81              Integer code=(Integer)request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
82              if (code!=null)
83              {
84                  error_page= (String)_errorPages.get(Integer.toString(code));
85  
86                  // if still not found
87                  if ((error_page == null) && (_errorPageList != null))
88                  {
89                      // look for an error code range match.
90                      for (int i = 0; i < _errorPageList.size(); i++)
91                      {
92                          ErrorCodeRange errCode = (ErrorCodeRange) _errorPageList.get(i);
93                          if (errCode.isInRange(code))
94                          {
95                              error_page = errCode.getUri();
96                              break;
97                          }
98                      }
99                  }
100             }
101         }
102 
103         //try new servlet 3.0 global error page
104         if (error_page == null)
105         {
106             error_page = _errorPages.get(GLOBAL_ERROR_PAGE);
107         }
108 
109         return error_page;
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 }