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  /** Error Page Error Handler
35   *
36   * An ErrorHandler that maps exceptions and status codes to URIs for dispatch using
37   * the internal ERROR style of dispatch.
38   *
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      protected Map _errorPages; // code or exception to URL
47      protected List _errorPageList; // 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      public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
58      {
59          String method = request.getMethod();
60          if(!method.equals(HttpMethods.GET) && !method.equals(HttpMethods.POST) && !method.equals(HttpMethods.HEAD))
61          {
62              HttpConnection.getCurrentConnection().getRequest().setHandled(true);
63              return;
64          }
65          if (_errorPages!=null)
66          {
67              String error_page= null;
68              Class exClass= (Class)request.getAttribute(Dispatcher.ERROR_EXCEPTION_TYPE);
69  
70              if (ServletException.class.equals(exClass))
71              {
72                  error_page= (String)_errorPages.get(exClass.getName());
73                  if (error_page == null)
74                  {
75                      Throwable th= (Throwable)request.getAttribute(Dispatcher.ERROR_EXCEPTION);
76                      while (th instanceof ServletException)
77                          th= ((ServletException)th).getRootCause();
78                      if (th != null)
79                          exClass= th.getClass();
80                  }
81              }
82  
83              while (error_page == null && exClass != null )
84              {
85                  error_page= (String)_errorPages.get(exClass.getName());
86                  exClass= exClass.getSuperclass();
87              }
88  
89              if (error_page == null)
90              {
91                  // look for an exact code match
92                  Integer code=(Integer)request.getAttribute(Dispatcher.ERROR_STATUS_CODE);
93                  if (code!=null)
94                  {
95                      error_page= (String)_errorPages.get(Integer.toString(code));
96  
97                      // if still not found
98                      if ((error_page == null) && (_errorPageList != null))
99                      {
100                         // look for an error code range match.
101                         for (int i = 0; i < _errorPageList.size(); i++)
102                         {
103                             ErrorCodeRange errCode = (ErrorCodeRange) _errorPageList.get(i);
104                             if (errCode.isInRange(code))
105                             {
106                                 error_page = errCode.getUri();
107                                 break;
108                             }
109                         }
110                     }
111                 }
112             }
113 
114             if (error_page!=null)
115             {
116                 String old_error_page=(String)request.getAttribute(ERROR_PAGE);
117                 if (old_error_page==null || !old_error_page.equals(error_page))
118                 {
119                     request.setAttribute(ERROR_PAGE, error_page);
120 
121                     Dispatcher dispatcher = (Dispatcher) _servletContext.getRequestDispatcher(error_page);
122                     try
123                     {
124                         if(dispatcher!=null)
125                         {
126                             dispatcher.error(request, response);
127                             return;
128                         }
129                         else
130                         {
131                             Log.warn("No error page "+error_page);
132                         }
133                     }
134                     catch (ServletException e)
135                     {
136                         Log.warn(Log.EXCEPTION, e);
137                         return;
138                     }
139                 }
140             }
141         }
142 
143         super.handle(target, baseRequest, request, response);
144     }
145 
146     /* ------------------------------------------------------------ */
147     /**
148      * @return Returns the errorPages.
149      */
150     public Map getErrorPages()
151     {
152         return _errorPages;
153     }
154 
155     /* ------------------------------------------------------------ */
156     /**
157      * @param errorPages The errorPages to set. A map of Exception class name  or error code as a string to URI string
158      */
159     public void setErrorPages(Map errorPages)
160     {
161         _errorPages = errorPages;
162     }
163 
164     /* ------------------------------------------------------------ */
165     /** Add Error Page mapping for an exception class
166      * This method is called as a result of an exception-type element in a web.xml file
167      * or may be called directly
168      * @param exception The exception
169      * @param uri The URI of the error page.
170      */
171     public void addErrorPage(Class exception,String uri)
172     {
173         if (_errorPages==null)
174             _errorPages=new HashMap();
175         _errorPages.put(exception.getName(),uri);
176     }
177 
178     /* ------------------------------------------------------------ */
179     /** Add Error Page mapping for a status code.
180      * This method is called as a result of an error-code element in a web.xml file
181      * or may be called directly
182      * @param code The HTTP status code to match
183      * @param uri The URI of the error page.
184      */
185     public void addErrorPage(int code,String uri)
186     {
187         if (_errorPages==null)
188             _errorPages=new HashMap();
189         _errorPages.put(Integer.toString(code),uri);
190     }
191 
192     /* ------------------------------------------------------------ */
193     /** Add Error Page mapping for a status code range.
194      * This method is not available from web.xml and must be called
195      * directly.
196      * @param from The lowest matching status code
197      * @param to The highest matching status code
198      * @param uri The URI of the error page.
199      */
200     public void addErrorPage(int from, int to, String uri)
201     {
202         if (_errorPageList == null)
203         {
204             _errorPageList = new ArrayList();
205         }
206         _errorPageList.add(new ErrorCodeRange(from, to, uri));
207     }
208 
209     /* ------------------------------------------------------------ */
210     protected void doStart() throws Exception
211     {
212         super.doStart();
213         _servletContext=ContextHandler.getCurrentContext();
214     }
215 
216     /* ------------------------------------------------------------ */
217     protected void doStop() throws Exception
218     {
219         // TODO Auto-generated method stub
220         super.doStop();
221     }
222 
223     /* ------------------------------------------------------------ */
224     /* ------------------------------------------------------------ */
225     private class ErrorCodeRange
226     {
227         private int _from;
228         private int _to;
229         private String _uri;
230 
231         ErrorCodeRange(int from, int to, String uri)
232             throws IllegalArgumentException
233         {
234             if (from > to)
235                 throw new IllegalArgumentException("from>to");
236 
237             _from = from;
238             _to = to;
239             _uri = uri;
240         }
241 
242         boolean isInRange(int value)
243         {
244             if ((value >= _from) && (value <= _to))
245             {
246                 return true;
247             }
248 
249             return false;
250         }
251 
252         String getUri()
253         {
254             return _uri;
255         }
256 
257         public String toString()
258         {
259             return "from: " + _from + ",to: " + _to + ",uri: " + _uri;
260         }
261     }
262 }