View Javadoc

1   // ========================================================================
2   // Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses.
12  // ========================================================================
13  
14  package org.eclipse.jetty.servlet;
15  
16  import java.io.IOException;
17  import java.util.ArrayList;
18  import java.util.HashMap;
19  import java.util.List;
20  import java.util.Map;
21  import javax.servlet.ServletContext;
22  import javax.servlet.ServletException;
23  import javax.servlet.http.HttpServletRequest;
24  import javax.servlet.http.HttpServletResponse;
25  
26  import org.eclipse.jetty.http.HttpMethods;
27  import org.eclipse.jetty.server.Dispatcher;
28  import org.eclipse.jetty.server.HttpConnection;
29  import org.eclipse.jetty.server.Request;
30  import org.eclipse.jetty.server.handler.ContextHandler;
31  import org.eclipse.jetty.server.handler.ErrorHandler;
32  import org.eclipse.jetty.util.log.Log;
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
42  {
43      public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page";
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      /**
55       * @see org.eclipse.jetty.server.handler.ErrorHandler#handle(String, Request, HttpServletRequest, HttpServletResponse)
56       */
57      @Override
58      public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
59      {
60          String method = request.getMethod();
61          if(!method.equals(HttpMethods.GET) && !method.equals(HttpMethods.POST) && !method.equals(HttpMethods.HEAD))
62          {
63              HttpConnection.getCurrentConnection().getRequest().setHandled(true);
64              return;
65          }
66          if (_errorPages!=null)
67          {
68              String error_page= null;
69              Class<?> exClass= (Class<?>)request.getAttribute(Dispatcher.ERROR_EXCEPTION_TYPE);
70  
71              if (ServletException.class.equals(exClass))
72              {
73                  error_page= (String)_errorPages.get(exClass.getName());
74                  if (error_page == null)
75                  {
76                      Throwable th= (Throwable)request.getAttribute(Dispatcher.ERROR_EXCEPTION);
77                      while (th instanceof ServletException)
78                          th= ((ServletException)th).getRootCause();
79                      if (th != null)
80                          exClass= th.getClass();
81                  }
82              }
83  
84              while (error_page == null && exClass != null )
85              {
86                  error_page= (String)_errorPages.get(exClass.getName());
87                  exClass= exClass.getSuperclass();
88              }
89  
90              if (error_page == null)
91              {
92                  // look for an exact code match
93                  Integer code=(Integer)request.getAttribute(Dispatcher.ERROR_STATUS_CODE);
94                  if (code!=null)
95                  {
96                      error_page= (String)_errorPages.get(Integer.toString(code));
97  
98                      // if still not found
99                      if ((error_page == null) && (_errorPageList != null))
100                     {
101                         // look for an error code range match.
102                         for (int i = 0; i < _errorPageList.size(); i++)
103                         {
104                             ErrorCodeRange errCode = (ErrorCodeRange) _errorPageList.get(i);
105                             if (errCode.isInRange(code))
106                             {
107                                 error_page = errCode.getUri();
108                                 break;
109                             }
110                         }
111                     }
112                 }
113             }
114 
115             if (error_page!=null)
116             {
117                 String old_error_page=(String)request.getAttribute(ERROR_PAGE);
118                 if (old_error_page==null || !old_error_page.equals(error_page))
119                 {
120                     request.setAttribute(ERROR_PAGE, error_page);
121 
122                     Dispatcher dispatcher = (Dispatcher) _servletContext.getRequestDispatcher(error_page);
123                     try
124                     {
125                         if(dispatcher!=null)
126                         {
127                             dispatcher.error(request, response);
128                             return;
129                         }
130                         else
131                         {
132                             Log.warn("No error page "+error_page);
133                         }
134                     }
135                     catch (ServletException e)
136                     {
137                         Log.warn(Log.EXCEPTION, e);
138                         return;
139                     }
140                 }
141             }
142         }
143 
144         super.handle(target, baseRequest, request, response);
145     }
146 
147     /* ------------------------------------------------------------ */
148     /**
149      * @return Returns the errorPages.
150      */
151     public Map<String,String> getErrorPages()
152     {
153         return _errorPages;
154     }
155 
156     /* ------------------------------------------------------------ */
157     /**
158      * @param errorPages The errorPages to set. A map of Exception class name  or error code as a string to URI string
159      */
160     public void setErrorPages(Map<String,String> errorPages)
161     {
162         _errorPages.clear();
163         if (errorPages!=null)
164             _errorPages.putAll(errorPages);
165     }
166 
167     /* ------------------------------------------------------------ */
168     /** Add Error Page mapping for an exception class
169      * This method is called as a result of an exception-type element in a web.xml file
170      * or may be called directly
171      * @param exception The exception
172      * @param uri The URI of the error page.
173      */
174     public void addErrorPage(Class<? extends Throwable> exception,String uri)
175     {
176         _errorPages.put(exception.getName(),uri);
177     }
178     
179     /* ------------------------------------------------------------ */
180     /** Add Error Page mapping for an exception class
181      * This method is called as a result of an exception-type element in a web.xml file
182      * or may be called directly
183      * @param exceptionClassName The exception
184      * @param uri The URI of the error page.
185      */
186     public void addErrorPage(String exceptionClassName,String uri)
187     {
188         _errorPages.put(exceptionClassName,uri);
189     }
190 
191     /* ------------------------------------------------------------ */
192     /** Add Error Page mapping for a status code.
193      * This method is called as a result of an error-code element in a web.xml file
194      * or may be called directly
195      * @param code The HTTP status code to match
196      * @param uri The URI of the error page.
197      */
198     public void addErrorPage(int code,String uri)
199     {
200         _errorPages.put(Integer.toString(code),uri);
201     }
202 
203     /* ------------------------------------------------------------ */
204     /** Add Error Page mapping for a status code range.
205      * This method is not available from web.xml and must be called
206      * directly.
207      * @param from The lowest matching status code
208      * @param to The highest matching status code
209      * @param uri The URI of the error page.
210      */
211     public void addErrorPage(int from, int to, String uri)
212     {
213         _errorPageList.add(new ErrorCodeRange(from, to, uri));
214     }
215 
216     /* ------------------------------------------------------------ */
217     @Override
218     protected void doStart() throws Exception
219     {
220         super.doStart();
221         _servletContext=ContextHandler.getCurrentContext();
222     }
223 
224     /* ------------------------------------------------------------ */
225     @Override
226     protected void doStop() throws Exception
227     {
228         // TODO Auto-generated method stub
229         super.doStop();
230     }
231 
232     /* ------------------------------------------------------------ */
233     /* ------------------------------------------------------------ */
234     private class ErrorCodeRange
235     {
236         private int _from;
237         private int _to;
238         private String _uri;
239 
240         ErrorCodeRange(int from, int to, String uri)
241             throws IllegalArgumentException
242         {
243             if (from > to)
244                 throw new IllegalArgumentException("from>to");
245 
246             _from = from;
247             _to = to;
248             _uri = uri;
249         }
250 
251         boolean isInRange(int value)
252         {
253             if ((value >= _from) && (value <= _to))
254             {
255                 return true;
256             }
257 
258             return false;
259         }
260 
261         String getUri()
262         {
263             return _uri;
264         }
265 
266         @Override
267         public String toString()
268         {
269             return "from: " + _from + ",to: " + _to + ",uri: " + _uri;
270         }
271     }
272 }