1 // 2 // ======================================================================== 3 // Copyright (c) 1995-2014 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 /* ------------------------------------------------------------ */ ErrorPageErrorHandler()50 public ErrorPageErrorHandler() 51 {} 52 53 @Override getErrorPage(HttpServletRequest request)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 */ getErrorPages()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 */ setErrorPages(Map<String,String> errorPages)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 */ addErrorPage(Class<? extends Throwable> exception,String uri)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 */ addErrorPage(String exceptionClassName,String uri)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 */ addErrorPage(int code,String uri)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 */ addErrorPage(int from, int to, String uri)176 public void addErrorPage(int from, int to, String uri) 177 { 178 _errorPageList.add(new ErrorCodeRange(from, to, uri)); 179 } 180 181 /* ------------------------------------------------------------ */ 182 @Override doStart()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 ErrorCodeRange(int from, int to, String uri)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 isInRange(int value)208 boolean isInRange(int value) 209 { 210 if ((value >= _from) && (value <= _to)) 211 { 212 return true; 213 } 214 215 return false; 216 } 217 getUri()218 String getUri() 219 { 220 return _uri; 221 } 222 223 @Override toString()224 public String toString() 225 { 226 return "from: " + _from + ",to: " + _to + ",uri: " + _uri; 227 } 228 } 229 } 230