1 // ======================================================================== 2 // Copyright 2006 Mort Bay Consulting Pty. Ltd. 3 // ------------------------------------------------------------------------ 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 // ======================================================================== 14 15 package org.mortbay.jetty.servlet; 16 17 import java.io.IOException; 18 import java.util.ArrayList; 19 import java.util.HashMap; 20 import java.util.List; 21 import java.util.Map; 22 23 import javax.servlet.ServletContext; 24 import javax.servlet.ServletException; 25 import javax.servlet.http.HttpServletRequest; 26 import javax.servlet.http.HttpServletResponse; 27 28 import org.mortbay.jetty.HttpConnection; 29 import org.mortbay.jetty.HttpMethods; 30 import org.mortbay.jetty.handler.ContextHandler; 31 import org.mortbay.jetty.handler.ErrorHandler; 32 import org.mortbay.jetty.webapp.WebAppContext; 33 import org.mortbay.log.Log; 34 import org.mortbay.util.TypeUtil; 35 36 /** Error Page Error Handler 37 * 38 * An ErrorHandler that maps exceptions and status codes to URIs for dispatch using 39 * the internal ERROR style of dispatch. 40 * @author gregw 41 * 42 */ 43 public class ErrorPageErrorHandler extends ErrorHandler 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 /** 51 * @param context 52 */ ErrorPageErrorHandler()53 public ErrorPageErrorHandler() 54 {} 55 56 /* ------------------------------------------------------------ */ 57 /* 58 * @see org.mortbay.jetty.handler.ErrorHandler#handle(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int) 59 */ handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch)60 public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException 61 { 62 String method = request.getMethod(); 63 if(!method.equals(HttpMethods.GET) && !method.equals(HttpMethods.POST)) 64 { 65 HttpConnection.getCurrentConnection().getRequest().setHandled(true); 66 return; 67 } 68 if (_errorPages!=null) 69 { 70 String error_page= null; 71 Class exClass= (Class)request.getAttribute(ServletHandler.__J_S_ERROR_EXCEPTION_TYPE); 72 73 if (ServletException.class.equals(exClass)) 74 { 75 error_page= (String)_errorPages.get(exClass.getName()); 76 if (error_page == null) 77 { 78 Throwable th= (Throwable)request.getAttribute(ServletHandler.__J_S_ERROR_EXCEPTION); 79 while (th instanceof ServletException) 80 th= ((ServletException)th).getRootCause(); 81 if (th != null) 82 exClass= th.getClass(); 83 } 84 } 85 86 while (error_page == null && exClass != null ) 87 { 88 error_page= (String)_errorPages.get(exClass.getName()); 89 exClass= exClass.getSuperclass(); 90 } 91 92 if (error_page == null) 93 { 94 // look for an exact code match 95 Integer code=(Integer)request.getAttribute(ServletHandler.__J_S_ERROR_STATUS_CODE); 96 if (code!=null) 97 { 98 error_page= (String)_errorPages.get(TypeUtil.toString(code.intValue())); 99 100 // if still not found 101 if ((error_page == null) && (_errorPageList != null)) 102 { 103 // look for an error code range match. 104 for (int i = 0; i < _errorPageList.size(); i++) 105 { 106 ErrorCodeRange errCode = (ErrorCodeRange) _errorPageList.get(i); 107 if (errCode.isInRange(code.intValue())) 108 { 109 error_page = errCode.getUri(); 110 break; 111 } 112 } 113 } 114 } 115 } 116 117 if (error_page!=null) 118 { 119 String old_error_page=(String)request.getAttribute(WebAppContext.ERROR_PAGE); 120 if (old_error_page==null || !old_error_page.equals(error_page)) 121 { 122 request.setAttribute(WebAppContext.ERROR_PAGE, error_page); 123 124 Dispatcher dispatcher = (Dispatcher) _servletContext.getRequestDispatcher(error_page); 125 try 126 { 127 if(dispatcher!=null) 128 { 129 dispatcher.error(request, response); 130 return; 131 } 132 else 133 { 134 Log.warn("No error page "+error_page); 135 } 136 } 137 catch (ServletException e) 138 { 139 Log.warn(Log.EXCEPTION, e); 140 return; 141 } 142 } 143 } 144 } 145 146 super.handle(target, request, response, dispatch); 147 } 148 149 /* ------------------------------------------------------------ */ 150 /** 151 * @return Returns the errorPages. 152 */ getErrorPages()153 public Map getErrorPages() 154 { 155 return _errorPages; 156 } 157 158 /* ------------------------------------------------------------ */ 159 /** 160 * @param errorPages The errorPages to set. A map of Exception class name or error code as a string to URI string 161 */ setErrorPages(Map errorPages)162 public void setErrorPages(Map errorPages) 163 { 164 _errorPages = 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 code The class (or superclass) of the matching exceptions 172 * @param uri The URI of the error page. 173 */ addErrorPage(Class exception,String uri)174 public void addErrorPage(Class exception,String uri) 175 { 176 if (_errorPages==null) 177 _errorPages=new HashMap(); 178 _errorPages.put(exception.getName(),uri); 179 } 180 181 /* ------------------------------------------------------------ */ 182 /** Add Error Page mapping for a status code. 183 * This method is called as a result of an error-code element in a web.xml file 184 * or may be called directly 185 * @param code The HTTP status code to match 186 * @param uri The URI of the error page. 187 */ addErrorPage(int code,String uri)188 public void addErrorPage(int code,String uri) 189 { 190 if (_errorPages==null) 191 _errorPages=new HashMap(); 192 _errorPages.put(TypeUtil.toString(code),uri); 193 } 194 195 /* ------------------------------------------------------------ */ 196 /** Add Error Page mapping for a status code range. 197 * This method is not available from web.xml and must be called 198 * directly. 199 * @param from The lowest matching status code 200 * @param to The highest matching status code 201 * @param uri The URI of the error page. 202 */ addErrorPage(int from, int to, String uri)203 public void addErrorPage(int from, int to, String uri) 204 { 205 if (_errorPageList == null) 206 { 207 _errorPageList = new ArrayList(); 208 } 209 _errorPageList.add(new ErrorCodeRange(from, to, uri)); 210 } 211 212 /* ------------------------------------------------------------ */ doStart()213 protected void doStart() throws Exception 214 { 215 super.doStart(); 216 _servletContext=ContextHandler.getCurrentContext(); 217 } 218 219 /* ------------------------------------------------------------ */ doStop()220 protected void doStop() throws Exception 221 { 222 // TODO Auto-generated method stub 223 super.doStop(); 224 } 225 226 /* ------------------------------------------------------------ */ 227 /* ------------------------------------------------------------ */ 228 private class ErrorCodeRange 229 { 230 private int _from; 231 private int _to; 232 private String _uri; 233 ErrorCodeRange(int from, int to, String uri)234 ErrorCodeRange(int from, int to, String uri) 235 throws IllegalArgumentException 236 { 237 if (from > to) 238 throw new IllegalArgumentException("from>to"); 239 240 _from = from; 241 _to = to; 242 _uri = uri; 243 } 244 isInRange(int value)245 boolean isInRange(int value) 246 { 247 if ((value >= _from) && (value <= _to)) 248 { 249 return true; 250 } 251 252 return false; 253 } 254 getUri()255 String getUri() 256 { 257 return _uri; 258 } 259 toString()260 public String toString() 261 { 262 return "from: " + _from + ",to: " + _to + ",uri: " + _uri; 263 } 264 } 265 }